mirror of https://github.com/statping/statping
vue
parent
f62dcd4336
commit
e0288b21a4
|
@ -11,12 +11,10 @@ An easy to use Status Page for your websites and applications. Statping will aut
|
|||
|
||||
[](https://godoc.org/github.com/statping/statping) [](https://gitter.im/statping/general) [](https://microbadger.com/images/hunterlong/statping) [](https://hub.docker.com/r/hunterlong/statping/builds/)
|
||||
|
||||
## A Future-Proof Status Page
|
||||
Statping strives to remain future-proof and remain intact if a failure is created. Your Statping service should not be running on the same instance you're trying to monitor. If your server crashes your Status Page should still remaining online to notify your users of downtime.
|
||||
<img align="left" width="320" height="235" src="https://img.cjx.io/statupsiterun.gif">
|
||||
|
||||
<p align="center">
|
||||
<img width="80%" src="https://img.cjx.io/statupsiterun.gif">
|
||||
</p>
|
||||
<h2>A Future-Proof Status Page</h2>
|
||||
Statping strives to remain future-proof and remain intact if a failure is created. Your Statping service should not be running on the same instance you're trying to monitor. If your server crashes your Status Page should still remaining online to notify your users of downtime.
|
||||
|
||||
## Lightweight and Fast
|
||||
Statping is a very lightweight application and is available for Linux, Mac, and Windows. The Docker image is only ~16Mb so you know that this application won't be filling up your hard drive space.
|
||||
|
|
19
cmd/main.go
19
cmd/main.go
|
@ -28,7 +28,6 @@ import (
|
|||
"github.com/statping/statping/source"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/handlers"
|
||||
"github.com/statping/statping/types/configs"
|
||||
"github.com/statping/statping/types/core"
|
||||
|
@ -47,6 +46,8 @@ var (
|
|||
port int
|
||||
log = utils.Log.WithField("type", "cmd")
|
||||
httpServer = make(chan bool)
|
||||
|
||||
confgs *configs.DbConfig
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -119,29 +120,29 @@ func main() {
|
|||
log.Errorln(err)
|
||||
}
|
||||
|
||||
c, err := configs.LoadConfigs()
|
||||
confgs, err = configs.LoadConfigs()
|
||||
if err != nil {
|
||||
if err := SetupMode(); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = configs.ConnectConfigs(c); err != nil {
|
||||
if err = configs.ConnectConfigs(confgs); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
||||
exists := database.DB().HasTable("core")
|
||||
exists := confgs.Db.HasTable("core")
|
||||
if !exists {
|
||||
|
||||
if err := c.DropDatabase(); err != nil {
|
||||
if err := confgs.DropDatabase(); err != nil {
|
||||
exit(errors.Wrap(err, "error dropping database"))
|
||||
}
|
||||
|
||||
if err := configs.CreateDatabase(); err != nil {
|
||||
if err := confgs.CreateDatabase(); err != nil {
|
||||
exit(errors.Wrap(err, "error creating database"))
|
||||
}
|
||||
|
||||
if err := configs.CreateAdminUser(c); err != nil {
|
||||
if err := configs.CreateAdminUser(confgs); err != nil {
|
||||
exit(errors.Wrap(err, "error creating default admin user"))
|
||||
}
|
||||
|
||||
|
@ -151,7 +152,7 @@ func main() {
|
|||
|
||||
}
|
||||
|
||||
if err := c.MigrateDatabase(); err != nil {
|
||||
if err := confgs.MigrateDatabase(); err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,7 @@ func main() {
|
|||
func Close() {
|
||||
sentry.Flush(3 * time.Second)
|
||||
utils.CloseLogs()
|
||||
database.Close()
|
||||
confgs.Close()
|
||||
}
|
||||
|
||||
func SetupMode() error {
|
||||
|
|
|
@ -18,9 +18,7 @@ const (
|
|||
TIME_DAY = "2006-01-02"
|
||||
)
|
||||
|
||||
var (
|
||||
database Database
|
||||
)
|
||||
var database Database
|
||||
|
||||
// Database is an interface which DB implements
|
||||
type Database interface {
|
||||
|
@ -112,39 +110,35 @@ type Database interface {
|
|||
DbType() string
|
||||
}
|
||||
|
||||
func DB() Database {
|
||||
return database
|
||||
}
|
||||
|
||||
func (it *Db) DbType() string {
|
||||
return it.Database.Dialect().GetName()
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
if database == nil {
|
||||
func Close(db Database) error {
|
||||
if db == nil {
|
||||
return nil
|
||||
}
|
||||
return database.Close()
|
||||
return db.Close()
|
||||
}
|
||||
|
||||
func LogMode(b bool) Database {
|
||||
return database.LogMode(b)
|
||||
func LogMode(db Database, b bool) Database {
|
||||
return db.LogMode(b)
|
||||
}
|
||||
|
||||
func Begin(model interface{}) Database {
|
||||
func Begin(db Database, model interface{}) Database {
|
||||
if all, ok := model.(string); ok {
|
||||
if all == "migration" {
|
||||
return database.Begin()
|
||||
return db.Begin()
|
||||
}
|
||||
}
|
||||
return database.Model(model).Begin()
|
||||
return db.Model(model).Begin()
|
||||
}
|
||||
|
||||
func Available() bool {
|
||||
if database == nil {
|
||||
func Available(db Database) bool {
|
||||
if db == nil {
|
||||
return false
|
||||
}
|
||||
if err := database.DB().Ping(); err != nil {
|
||||
if err := db.DB().Ping(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -179,11 +173,15 @@ func Openw(dialect string, args ...interface{}) (db Database, err error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db = Wrap(gormdb)
|
||||
database = db
|
||||
database = Wrap(gormdb)
|
||||
return database, err
|
||||
}
|
||||
|
||||
func OpenTester() (Database, error) {
|
||||
newDb, err := Openw("sqlite3", ":memory:?cache=shared")
|
||||
return newDb, err
|
||||
}
|
||||
|
||||
// Wrap wraps gorm.DB in an interface
|
||||
func Wrap(db *gorm.DB) Database {
|
||||
return &Db{
|
||||
|
|
|
@ -50,11 +50,11 @@ var (
|
|||
ByAverage = func(column string, multiplier int) By {
|
||||
switch database.DbType() {
|
||||
case "mysql":
|
||||
return By(fmt.Sprintf("CAST(AVG(%s)*%d as UNSIGNED) as amount", column, multiplier))
|
||||
return By(fmt.Sprintf("CAST(AVG(%s) as UNSIGNED) as amount", column))
|
||||
case "postgres":
|
||||
return By(fmt.Sprintf("cast(AVG(%s)*%d as int) as amount", column, multiplier))
|
||||
return By(fmt.Sprintf("cast(AVG(%s) as int) as amount", column))
|
||||
default:
|
||||
return By(fmt.Sprintf("cast(AVG(%s)*%d as int) as amount", column, multiplier))
|
||||
return By(fmt.Sprintf("cast(AVG(%s) as int) as amount", column))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -157,7 +157,7 @@ func ParseQueries(r *http.Request, o isObject) *GroupQuery {
|
|||
limit = 10000
|
||||
}
|
||||
|
||||
db := o.Db()
|
||||
q := o.Db()
|
||||
|
||||
if grouping == "" {
|
||||
grouping = "1h"
|
||||
|
@ -176,7 +176,7 @@ func ParseQueries(r *http.Request, o isObject) *GroupQuery {
|
|||
Limit: int(limit),
|
||||
Offset: int(offset),
|
||||
FillEmpty: fill,
|
||||
db: db,
|
||||
db: q,
|
||||
}
|
||||
|
||||
if startField == 0 {
|
||||
|
@ -190,18 +190,18 @@ func ParseQueries(r *http.Request, o isObject) *GroupQuery {
|
|||
}
|
||||
|
||||
if query.Limit != 0 {
|
||||
db = db.Limit(query.Limit)
|
||||
q = q.Limit(query.Limit)
|
||||
}
|
||||
if query.Offset > 0 {
|
||||
db = db.Offset(query.Offset)
|
||||
q = q.Offset(query.Offset)
|
||||
}
|
||||
|
||||
db = db.Where("created_at BETWEEN ? AND ?", db.FormatTime(query.Start), db.FormatTime(query.End))
|
||||
q = q.Where("created_at BETWEEN ? AND ?", q.FormatTime(query.Start), q.FormatTime(query.End))
|
||||
|
||||
if query.Order != "" {
|
||||
db = db.Order(query.Order)
|
||||
q = q.Order(query.Order)
|
||||
}
|
||||
query.db = db
|
||||
query.db = q
|
||||
|
||||
return query
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ func databaseMaintence(dur time.Duration) {
|
|||
// DeleteAllSince will delete a specific table's records based on a time.
|
||||
func DeleteAllSince(table string, date time.Time) {
|
||||
sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, database.FormatTime(date))
|
||||
db := database.Exec(sql)
|
||||
if db.Error() != nil {
|
||||
log.Warnln(db.Error())
|
||||
q := database.Exec(sql)
|
||||
if q.Error() != nil {
|
||||
log.Warnln(q.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,22 @@ HTML,BODY {
|
|||
background-color: $background-color;
|
||||
}
|
||||
|
||||
|
||||
.chartmarker {
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.chartmarker SPAN {
|
||||
font-size: 11pt;
|
||||
display: block;
|
||||
color: #8b8b8b;
|
||||
}
|
||||
|
||||
.apexcharts-tooltip {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.contain-card {
|
||||
|
||||
.card-header {
|
||||
|
|
|
@ -4,19 +4,20 @@
|
|||
|
||||
<script>
|
||||
import Api from "../../API"
|
||||
const timeoptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||||
|
||||
const axisOptions = {
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
crosshairs: {
|
||||
show: false
|
||||
show: true
|
||||
},
|
||||
lines: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
enabled: true
|
||||
},
|
||||
axisTicks: {
|
||||
show: false
|
||||
|
@ -25,7 +26,7 @@
|
|||
show: false
|
||||
},
|
||||
marker: {
|
||||
show: false
|
||||
show: true
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -47,6 +48,9 @@
|
|||
showing: false,
|
||||
data: [],
|
||||
chartOptions: {
|
||||
noData: {
|
||||
text: 'Loading...'
|
||||
},
|
||||
chart: {
|
||||
height: 210,
|
||||
width: "100%",
|
||||
|
@ -76,21 +80,47 @@
|
|||
left: -10,
|
||||
}
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
type: "datetime",
|
||||
...axisOptions
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
...axisOptions
|
||||
labels: {
|
||||
show: false
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
marker: {
|
||||
show: false,
|
||||
theme: false,
|
||||
enabled: true,
|
||||
markers: {
|
||||
size: 0
|
||||
},
|
||||
custom: function({series, seriesIndex, dataPointIndex, w}) {
|
||||
let service = w.globals.seriesNames[0];
|
||||
let ts = w.globals;
|
||||
window.console.log(ts);
|
||||
let val = series[seriesIndex][dataPointIndex];
|
||||
if (val > 1000) {
|
||||
val = (val * 0.1).toFixed(0) + " milliseconds"
|
||||
} else {
|
||||
val = (val * 0.01).toFixed(0) + " microseconds"
|
||||
}
|
||||
return `<div class="chartmarker"><span>${service} Average Response</span> <span class="font-3">${val}</span></div>`
|
||||
},
|
||||
fixed: {
|
||||
enabled: true,
|
||||
position: 'topRight',
|
||||
offsetX: -30,
|
||||
offsetY: 0,
|
||||
},
|
||||
x: {
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
|
@ -132,6 +162,7 @@
|
|||
},
|
||||
methods: {
|
||||
async chartHits(group) {
|
||||
window.console.log(this.service.created_at)
|
||||
this.data = await Api.service_hits(this.service.id, this.toUnix(this.service.created_at), this.toUnix(new Date()), group, false)
|
||||
|
||||
if (this.data.length === 0 && group !== "1h") {
|
||||
|
@ -139,7 +170,7 @@
|
|||
}
|
||||
this.series = [{
|
||||
name: this.service.name,
|
||||
...this.convertToChartData(this.data)
|
||||
...this.convertToChartData(this.data, 0.01)
|
||||
}]
|
||||
this.ready = true
|
||||
}
|
||||
|
|
|
@ -127,13 +127,13 @@ func apiClearCacheHandler(w http.ResponseWriter, r *http.Request) {
|
|||
returnJson(output, w, r)
|
||||
}
|
||||
|
||||
func sendErrorJson(err error, w http.ResponseWriter, r *http.Request) {
|
||||
func sendErrorJson(err error, w http.ResponseWriter, r *http.Request, statusCode ...int) {
|
||||
log.Warnln(fmt.Errorf("sending error response for %v: %v", r.URL.String(), err.Error()))
|
||||
output := apiResponse{
|
||||
Status: "error",
|
||||
Error: err.Error(),
|
||||
}
|
||||
returnJson(output, w, r)
|
||||
returnJson(output, w, r, statusCode...)
|
||||
}
|
||||
|
||||
func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -43,7 +43,7 @@ func apiAllGroupHandler(r *http.Request) interface{} {
|
|||
func apiGroupHandler(w http.ResponseWriter, r *http.Request) {
|
||||
group, err := selectGroup(r)
|
||||
if err != nil {
|
||||
sendErrorJson(errors.Wrap(err, "group not found"), w, r)
|
||||
sendErrorJson(errors.Wrap(err, "group not found"), w, r, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
returnJson(group, w, r)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -286,8 +286,12 @@ func executeJSResponse(w http.ResponseWriter, r *http.Request, file string, data
|
|||
//}
|
||||
}
|
||||
|
||||
func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
|
||||
func returnJson(d interface{}, w http.ResponseWriter, r *http.Request, statusCode ...int) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if len(statusCode) != 0 {
|
||||
code := statusCode[0]
|
||||
w.WriteHeader(code)
|
||||
}
|
||||
json.NewEncoder(w).Encode(d)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
@ -10,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
func TestAttachment(t *testing.T) {
|
||||
err := notifiers.AttachNotifiers()
|
||||
err := notifiers.Migrate()
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -91,14 +91,14 @@ func prometheusHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
PrometheusComment(fmt.Sprintf("Service #%d '%s':", ser.Id, ser.Name))
|
||||
PrometheusExportKey("service_failures", id, name, ser.AllFailures().Count())
|
||||
PrometheusExportKey("service_latency", id, name, ser.Latency*100)
|
||||
PrometheusExportKey("service_latency", id, name, ser.Latency)
|
||||
PrometheusExportKey("service_online", id, name, online)
|
||||
PrometheusExportKey("service_status_code", id, name, ser.LastStatusCode)
|
||||
PrometheusExportKey("service_response_length", id, name, len([]byte(ser.LastResponse)))
|
||||
PrometheusExportKey("service_ping_time", id, name, ser.PingTime)
|
||||
PrometheusExportKey("service_last_latency", id, name, ser.LastLatency)
|
||||
PrometheusExportKey("service_last_lookup", id, name, ser.LastLookupTime)
|
||||
PrometheusExportKey("service_last_check", id, name, time.Now().Sub(ser.LastCheck).Milliseconds())
|
||||
PrometheusExportKey("service_last_check", id, name, utils.Now().Sub(ser.LastCheck).Milliseconds())
|
||||
//PrometheusExportKey("service_online_seconds", id, name, ser.SecondsOnline)
|
||||
//PrometheusExportKey("service_offline_seconds", id, name, ser.SecondsOffline)
|
||||
|
||||
|
|
|
@ -89,11 +89,11 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
service, err := serviceByID(r)
|
||||
if err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
sendErrorJson(err, w, r, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if err := DecodeJSON(r, &service); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
sendErrorJson(err, w, r, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -17,7 +17,6 @@ package handlers
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/notifiers"
|
||||
"github.com/statping/statping/types/configs"
|
||||
"github.com/statping/statping/types/core"
|
||||
|
@ -62,14 +61,14 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
exists := database.DB().HasTable("core")
|
||||
exists := confgs.Db.HasTable("core")
|
||||
if !exists {
|
||||
if err := confgs.DropDatabase(); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if err := configs.CreateDatabase(); err != nil {
|
||||
if err := confgs.CreateDatabase(); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build int
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
|
|
|
@ -20,9 +20,9 @@ package source
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/russross/blackfriday/v2"
|
||||
"github.com/statping/statping/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
package checkins
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testCheckin = &Checkin{
|
||||
ServiceId: 1,
|
||||
Name: "Test Checkin",
|
||||
Interval: 60,
|
||||
GracePeriod: 10,
|
||||
ApiKey: "tHiSiSaTeStXXX",
|
||||
CreatedAt: utils.Now(),
|
||||
UpdatedAt: utils.Now(),
|
||||
LastHitTime: utils.Now().Add(-15 * time.Second),
|
||||
}
|
||||
|
||||
var testCheckinHits = []*CheckinHit{{
|
||||
Checkin: 1,
|
||||
From: "0.0.0.0.0",
|
||||
CreatedAt: utils.Now().Add(-30 * time.Second),
|
||||
}, {
|
||||
Checkin: 2,
|
||||
From: "0.0.0.0",
|
||||
CreatedAt: utils.Now().Add(-180 * time.Second),
|
||||
}}
|
||||
|
||||
var testApiKey string
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.AutoMigrate(&Checkin{}, &CheckinHit{}, &failures.Failure{})
|
||||
db.Create(&testCheckin)
|
||||
for _, v := range testCheckinHits {
|
||||
db.Create(&v)
|
||||
}
|
||||
assert.True(t, db.HasTable(&Checkin{}))
|
||||
assert.True(t, db.HasTable(&CheckinHit{}))
|
||||
assert.True(t, db.HasTable(&failures.Failure{}))
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Test Checkin", item.Name)
|
||||
assert.NotEmpty(t, item.ApiKey)
|
||||
testApiKey = item.ApiKey
|
||||
}
|
||||
|
||||
func TestFindByAPI(t *testing.T) {
|
||||
item, err := FindByAPI(testApiKey)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Test Checkin", item.Name)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &Checkin{
|
||||
Name: "Example 2",
|
||||
}
|
||||
err := example.Create()
|
||||
example.Close()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "Example 2", example.Name)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
assert.NotEmpty(t, example.ApiKey)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Name = "Updated"
|
||||
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated", item.Name)
|
||||
item.Close()
|
||||
}
|
||||
|
||||
func TestCheckin_Expected(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
expected := item.Expected()
|
||||
assert.GreaterOrEqual(t, expected.Seconds(), float64(29))
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(2)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -5,48 +5,57 @@ import (
|
|||
"github.com/statping/statping/utils"
|
||||
)
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Checkin{})
|
||||
}
|
||||
var db database.Database
|
||||
var dbHits database.Database
|
||||
|
||||
func DBhits() database.Database {
|
||||
return database.DB().Model(&CheckinHit{})
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Checkin{})
|
||||
dbHits = database.Model(&CheckinHit{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Checkin, error) {
|
||||
var checkin Checkin
|
||||
db := DB().Where("id = ?", id).Find(&checkin)
|
||||
return &checkin, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&checkin)
|
||||
return &checkin, q.Error()
|
||||
}
|
||||
|
||||
func FindByAPI(key string) (*Checkin, error) {
|
||||
var checkin Checkin
|
||||
db := DB().Where("api = ?", key).Find(&checkin)
|
||||
return &checkin, db.Error()
|
||||
q := db.Where("api_key = ?", key).Find(&checkin)
|
||||
return &checkin, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Checkin {
|
||||
var checkins []*Checkin
|
||||
DB().Find(&checkins)
|
||||
db.Find(&checkins)
|
||||
return checkins
|
||||
}
|
||||
|
||||
func (c *Checkin) Create() error {
|
||||
c.ApiKey = utils.RandomString(7)
|
||||
db := DB().Create(c)
|
||||
q := db.Create(c)
|
||||
|
||||
c.Start()
|
||||
go c.CheckinRoutine()
|
||||
return db.Error()
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *Checkin) Update() error {
|
||||
db := DB().Update(c)
|
||||
return db.Error()
|
||||
q := db.Update(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *Checkin) Delete() error {
|
||||
c.Close()
|
||||
db := DB().Delete(c)
|
||||
return db.Error()
|
||||
q := dbHits.Where("checkin = ?", c.Id).Delete(&CheckinHit{})
|
||||
if err := q.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
q = db.Model(&Checkin{}).Delete(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
//func (c *Checkin) AfterDelete() error {
|
||||
// //q := dbHits.Where("checkin = ?", c.Id).Delete(&CheckinHit{})
|
||||
// return q.Error()
|
||||
//}
|
||||
|
|
|
@ -2,28 +2,28 @@ package checkins
|
|||
|
||||
func (c *Checkin) LastHit() *CheckinHit {
|
||||
var hit CheckinHit
|
||||
DBhits().Where("checkin = ?", c.Id).Limit(1).Find(&hit)
|
||||
dbHits.Where("checkin = ?", c.Id).Limit(1).Find(&hit)
|
||||
return &hit
|
||||
}
|
||||
|
||||
func (c *Checkin) Hits() []*CheckinHit {
|
||||
var hits []*CheckinHit
|
||||
DBhits().Where("checkin = ?", c.Id).Find(&hits)
|
||||
dbHits.Where("checkin = ?", c.Id).Find(&hits)
|
||||
c.AllHits = hits
|
||||
return hits
|
||||
}
|
||||
|
||||
func (c *CheckinHit) Create() error {
|
||||
db := DBhits().Create(c)
|
||||
return db.Error()
|
||||
q := dbHits.Create(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *CheckinHit) Update() error {
|
||||
db := DBhits().Update(c)
|
||||
return db.Error()
|
||||
q := dbHits.Update(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *CheckinHit) Delete() error {
|
||||
db := DBhits().Delete(c)
|
||||
return db.Error()
|
||||
q := dbHits.Delete(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
func (c *Checkin) CreateFailure(f *failures.Failure) error {
|
||||
f.Checkin = c.Id
|
||||
return failures.DB().Create(&f).Error()
|
||||
return failures.DB().Create(f).Error()
|
||||
}
|
||||
|
||||
func (c *Checkin) FailuresColumnID() (string, int64) {
|
||||
|
@ -19,5 +19,5 @@ func (c *Checkin) Failures() failures.Failurer {
|
|||
}
|
||||
|
||||
func (c *Checkin) FailuresSince(t time.Time) failures.Failurer {
|
||||
return failures.FailuresSince(t, c)
|
||||
return failures.Since(t, c)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package checkins
|
||||
|
||||
//go:generate counterfeiter . Checkin
|
|
@ -47,7 +47,7 @@ CheckinLoop:
|
|||
Method: "checkin",
|
||||
Service: c.ServiceId,
|
||||
Checkin: c.Id,
|
||||
PingTime: c.Expected().Seconds(),
|
||||
PingTime: c.Expected().Milliseconds(),
|
||||
CreatedAt: time.Time{},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package checkins
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/utils"
|
||||
"time"
|
||||
|
@ -32,24 +31,7 @@ type CheckinHit struct {
|
|||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
// BeforeCreate for checkinHit will set CreatedAt to UTC
|
||||
func (c *CheckinHit) BeforeCreate() (err error) {
|
||||
if c.CreatedAt.IsZero() {
|
||||
c.CreatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Checkin) BeforeCreate() (err error) {
|
||||
c.ApiKey = utils.RandomString(7)
|
||||
if c.CreatedAt.IsZero() {
|
||||
c.CreatedAt = time.Now().UTC()
|
||||
c.UpdatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Checkin) BeforeDelete(tx database.Database) (err error) {
|
||||
return tx.Where("id = ?", c.ServiceId).
|
||||
Update("group_id", 0).Error()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,16 @@ import (
|
|||
"github.com/jinzhu/gorm"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/groups"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/types/incidents"
|
||||
"github.com/statping/statping/types/messages"
|
||||
"github.com/statping/statping/types/notifications"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/types/users"
|
||||
"github.com/statping/statping/utils"
|
||||
"os"
|
||||
|
@ -15,9 +24,6 @@ import (
|
|||
// Connect will attempt to connect to the sqlite, postgres, or mysql database
|
||||
func Connect(configs *DbConfig, retry bool) error {
|
||||
postgresSSL := os.Getenv("POSTGRES_SSLMODE")
|
||||
if database.Available() {
|
||||
return nil
|
||||
}
|
||||
var conn string
|
||||
var err error
|
||||
|
||||
|
@ -25,7 +31,7 @@ func Connect(configs *DbConfig, retry bool) error {
|
|||
case "sqlite", "sqlite3", "memory":
|
||||
if configs.DbConn == "memory" {
|
||||
conn = "sqlite3"
|
||||
configs.DbConn = ":memory"
|
||||
configs.DbConn = ":memory:"
|
||||
} else {
|
||||
conn = findDbFile(configs)
|
||||
configs.SqlFile = conn
|
||||
|
@ -76,14 +82,31 @@ func Connect(configs *DbConfig, retry bool) error {
|
|||
|
||||
if dbSession.DB().Ping() == nil {
|
||||
if utils.VerboseMode >= 4 {
|
||||
database.LogMode(true).Debug().SetLogger(gorm.Logger{log})
|
||||
dbSession.LogMode(true).Debug().SetLogger(gorm.Logger{log})
|
||||
}
|
||||
log.Infoln(fmt.Sprintf("Database %v connection was successful.", configs.DbConn))
|
||||
}
|
||||
|
||||
configs.Db = dbSession
|
||||
|
||||
initModels(configs.Db)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func initModels(db database.Database) {
|
||||
core.SetDB(db)
|
||||
services.SetDB(db)
|
||||
hits.SetDB(db)
|
||||
failures.SetDB(db)
|
||||
checkins.SetDB(db)
|
||||
notifications.SetDB(db)
|
||||
incidents.SetDB(db)
|
||||
users.SetDB(db)
|
||||
messages.SetDB(db)
|
||||
groups.SetDB(db)
|
||||
}
|
||||
|
||||
func CreateAdminUser(configs *DbConfig) error {
|
||||
log.Infoln(fmt.Sprintf("Core database does not exist, creating now!"))
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ func (d *DbConfig) DropDatabase() error {
|
|||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
log.Infoln("Dropping Database Tables...")
|
||||
for _, t := range DbModels {
|
||||
if err := database.DB().DropTableIfExists(t); err != nil {
|
||||
if err := d.Db.DropTableIfExists(t); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
log.Infof("Dropped table: %T\n", t)
|
||||
|
@ -84,19 +84,23 @@ func (d *DbConfig) DropDatabase() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *DbConfig) Close() {
|
||||
d.Db.Close()
|
||||
}
|
||||
|
||||
// CreateDatabase will CREATE TABLES for each of the Statping elements
|
||||
func CreateDatabase() error {
|
||||
func (d *DbConfig) CreateDatabase() error {
|
||||
var err error
|
||||
|
||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
|
||||
log.Infoln("Creating Database Tables...")
|
||||
for _, table := range DbModels {
|
||||
if err := database.DB().CreateTable(table); err.Error() != nil {
|
||||
if err := d.Db.CreateTable(table); err.Error() != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
if err := database.DB().Table("core").CreateTable(&core.Core{}); err.Error() != nil {
|
||||
if err := d.Db.Table("core").CreateTable(&core.Core{}); err.Error() != nil {
|
||||
return err.Error()
|
||||
}
|
||||
log.Infoln("Statping Database Created")
|
||||
|
|
|
@ -2,7 +2,6 @@ package configs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/types/failures"
|
||||
|
@ -51,7 +50,7 @@ func (c *DbConfig) MigrateDatabase() error {
|
|||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||
|
||||
log.Infoln("Migrating Database Tables...")
|
||||
tx := database.Begin("migration")
|
||||
tx := c.Db.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
|
@ -75,19 +74,19 @@ func (c *DbConfig) MigrateDatabase() error {
|
|||
}
|
||||
log.Infoln("Statping Database Tables Migrated")
|
||||
|
||||
if err := database.DB().Model(&hits.Hit{}).AddIndex("idx_service_hit", "service").Error(); err != nil {
|
||||
if err := c.Db.Model(&hits.Hit{}).AddIndex("idx_service_hit", "service").Error(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
if err := database.DB().Model(&hits.Hit{}).AddIndex("hit_created_at", "created_at").Error(); err != nil {
|
||||
if err := c.Db.Model(&hits.Hit{}).AddIndex("hit_created_at", "created_at").Error(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
if err := database.DB().Model(&failures.Failure{}).AddIndex("idx_service_fail", "service").Error(); err != nil {
|
||||
if err := c.Db.Model(&failures.Failure{}).AddIndex("idx_service_fail", "service").Error(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
if err := database.DB().Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil {
|
||||
if err := c.Db.Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
log.Infoln("Database Indexes Created")
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
package configs
|
||||
|
||||
import (
|
||||
"github.com/romanyx/polluter"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/utils"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//func preparePostgresDB(t *testing.T) (database.Database, error) {
|
||||
// dbName := fmt.Sprintf("db_%d", time.Now().UnixNano())
|
||||
// db, err := database.Openw("sqlite3", dbName)
|
||||
|
@ -17,20 +9,3 @@ import (
|
|||
//
|
||||
// return db, db.Error()
|
||||
//}
|
||||
|
||||
func TestSeedDatabase(t *testing.T) {
|
||||
t.SkipNow()
|
||||
dir := utils.Directory
|
||||
f, err := os.Open(dir + "/testdata.yml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
p := polluter.New(polluter.PostgresEngine(database.DB().DB()))
|
||||
|
||||
if err := p.Pollute(f); err != nil {
|
||||
t.Fatalf("failed to pollute: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package configs
|
||||
|
||||
import "github.com/statping/statping/database"
|
||||
|
||||
const SqliteFilename = "statping.db"
|
||||
|
||||
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
|
||||
|
@ -23,4 +25,6 @@ type DbConfig struct {
|
|||
SqlFile string `yaml:"sqlfile,omitempty" json:"-"`
|
||||
LocalIP string `yaml:"-" json:"-"`
|
||||
filename string `yaml:"-" json:"-"`
|
||||
|
||||
Db database.Database `yaml:"-" json:"-"`
|
||||
}
|
||||
|
|
|
@ -9,27 +9,29 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Table("core")
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Core{})
|
||||
}
|
||||
|
||||
func Select() (*Core, error) {
|
||||
var c Core
|
||||
// SelectCore will return the CoreApp global variable and the settings/configs for Statping
|
||||
if !database.Available() {
|
||||
if err := db.DB().Ping(); err != nil {
|
||||
return nil, errors.New("database has not been initiated yet.")
|
||||
}
|
||||
exists := DB().HasTable("core")
|
||||
exists := db.HasTable("core")
|
||||
if !exists {
|
||||
return nil, errors.New("core database has not been setup yet.")
|
||||
}
|
||||
db := DB().Find(&c)
|
||||
if db.Error() != nil {
|
||||
q := db.Find(&c)
|
||||
if q.Error() != nil {
|
||||
return nil, db.Error()
|
||||
}
|
||||
App = &c
|
||||
App.UseCdn = null.NewNullBool(os.Getenv("USE_CDN") == "true")
|
||||
return App, db.Error()
|
||||
return App, q.Error()
|
||||
}
|
||||
|
||||
func (c *Core) Create() error {
|
||||
|
@ -44,13 +46,13 @@ func (c *Core) Create() error {
|
|||
Domain: c.Domain,
|
||||
MigrationId: time.Now().Unix(),
|
||||
}
|
||||
db := DB().Create(&newCore)
|
||||
return db.Error()
|
||||
q := db.Create(&newCore)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *Core) Update() error {
|
||||
db := DB().Update(c)
|
||||
return db.Error()
|
||||
q := db.Update(c)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (c *Core) Delete() error {
|
||||
|
@ -73,6 +75,6 @@ func Sample() error {
|
|||
Footer: null.NewNullString(""),
|
||||
}
|
||||
|
||||
db := DB().Create(core)
|
||||
return db.Error()
|
||||
q := db.Create(core)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -2,33 +2,39 @@ package failures
|
|||
|
||||
import "github.com/statping/statping/database"
|
||||
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Failure{})
|
||||
}
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Failure{})
|
||||
return db
|
||||
}
|
||||
|
||||
func Find(id int64) (*Failure, error) {
|
||||
var failure Failure
|
||||
db := DB().Where("id = ?", id).Find(&failure)
|
||||
return &failure, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&failure)
|
||||
return &failure, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Failure {
|
||||
var failures []*Failure
|
||||
DB().Find(&failures)
|
||||
db.Find(&failures)
|
||||
return failures
|
||||
}
|
||||
|
||||
func (f *Failure) Create() error {
|
||||
db := DB().Create(f)
|
||||
return db.Error()
|
||||
q := db.Create(f)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (f *Failure) Update() error {
|
||||
db := DB().Update(f)
|
||||
return db.Error()
|
||||
q := db.Update(f)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (f *Failure) Delete() error {
|
||||
db := DB().Delete(f)
|
||||
return db.Error()
|
||||
q := db.Delete(f)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -18,37 +18,54 @@ func (f Failurer) Db() database.Database {
|
|||
return f.db
|
||||
}
|
||||
|
||||
func (f Failurer) First() *Failure {
|
||||
var fail Failure
|
||||
f.db.Order("id ASC").Limit(1).Find(&fail)
|
||||
return &fail
|
||||
}
|
||||
|
||||
func (f Failurer) Last() *Failure {
|
||||
var fail Failure
|
||||
f.db.Order("id DESC").Limit(1).Find(&fail)
|
||||
return &fail
|
||||
}
|
||||
|
||||
func (f Failurer) List() []*Failure {
|
||||
var fails []*Failure
|
||||
f.db.Find(&fails)
|
||||
return fails
|
||||
}
|
||||
|
||||
func (f Failurer) LastAmount(amount int) []*Failure {
|
||||
var fail []*Failure
|
||||
f.db.Order("id asc").Limit(amount).Find(&fail)
|
||||
return fail
|
||||
}
|
||||
|
||||
func (f Failurer) Since(t time.Time) []*Failure {
|
||||
var fails []*Failure
|
||||
f.db.Since(t).Find(&fails)
|
||||
return fails
|
||||
}
|
||||
|
||||
func (f Failurer) Count() int {
|
||||
var amount int
|
||||
f.db.Count(&amount)
|
||||
return amount
|
||||
}
|
||||
|
||||
func (f Failurer) Last(amount int) []*Failure {
|
||||
var fails []*Failure
|
||||
f.db.Limit(amount).Find(&fails)
|
||||
return fails
|
||||
}
|
||||
|
||||
func (f Failurer) Since(t time.Time) []*Failure {
|
||||
var fails []*Failure
|
||||
f.db.Since(t).Find(&fails)
|
||||
return fails
|
||||
func (f Failurer) DeleteAll() error {
|
||||
q := f.db.Delete(&Failure{})
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func AllFailures(obj ColumnIDInterfacer) Failurer {
|
||||
column, id := obj.FailuresColumnID()
|
||||
return Failurer{DB().Where(fmt.Sprintf("%s = ?", column), id)}
|
||||
return Failurer{db.Where(fmt.Sprintf("%s = ?", column), id)}
|
||||
}
|
||||
|
||||
func FailuresSince(t time.Time, obj ColumnIDInterfacer) Failurer {
|
||||
func Since(t time.Time, obj ColumnIDInterfacer) Failurer {
|
||||
column, id := obj.FailuresColumnID()
|
||||
timestamp := DB().FormatTime(t)
|
||||
return Failurer{DB().Where(fmt.Sprintf("%s = ? AND created_at > ?", column), id, timestamp)}
|
||||
timestamp := db.FormatTime(t)
|
||||
return Failurer{db.Where(fmt.Sprintf("%s = ? AND created_at > ?", column), id, timestamp)}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
tx := DB().Begin()
|
||||
tx := db.Begin()
|
||||
sg := new(sync.WaitGroup)
|
||||
|
||||
createdAt := utils.Now().Add(-3 * types.Day)
|
||||
|
|
|
@ -17,18 +17,10 @@ type Failure struct {
|
|||
ErrorCode int `gorm:"column:error_code" json:"error_code"`
|
||||
Service int64 `gorm:"index;column:service" json:"-"`
|
||||
Checkin int64 `gorm:"index;column:checkin" json:"-"`
|
||||
PingTime float64 `gorm:"column:ping_time" json:"ping"`
|
||||
PingTime int64 `gorm:"column:ping_time" json:"ping"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
// BeforeCreate for Failure will set CreatedAt to UTC
|
||||
func (f *Failure) BeforeCreate() (err error) {
|
||||
if f.CreatedAt.IsZero() {
|
||||
f.CreatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type FailSort []Failure
|
||||
|
||||
func (s FailSort) Len() int {
|
||||
|
|
|
@ -5,35 +5,37 @@ import (
|
|||
"sort"
|
||||
)
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Group{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Group{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Group, error) {
|
||||
var group Group
|
||||
db := DB().Where("id = ?", id).Find(&group)
|
||||
return &group, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&group)
|
||||
return &group, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Group {
|
||||
var groups []*Group
|
||||
DB().Find(&groups)
|
||||
db.Find(&groups)
|
||||
return groups
|
||||
}
|
||||
|
||||
func (g *Group) Create() error {
|
||||
db := DB().Create(g)
|
||||
return db.Error()
|
||||
q := db.Create(g)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (g *Group) Update() error {
|
||||
db := DB().Update(g)
|
||||
return db.Error()
|
||||
q := db.Update(g)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (g *Group) Delete() error {
|
||||
db := DB().Delete(g)
|
||||
return db.Error()
|
||||
q := db.Delete(g)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
// SelectGroups returns all groups
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package groups
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var example = &Group{
|
||||
Name: "Example Group",
|
||||
Public: null.NewNullBool(true),
|
||||
Order: 1,
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.CreateTable(&Group{})
|
||||
db.Create(&example)
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Example Group", item.Name)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &Group{
|
||||
Name: "Example 2",
|
||||
Public: null.NewNullBool(false),
|
||||
Order: 3,
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "Example 2", example.Name)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Name = "Updated"
|
||||
item.Order = 1
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated", item.Name)
|
||||
}
|
||||
|
||||
func TestSelectGroups(t *testing.T) {
|
||||
groups := SelectGroups(true, true)
|
||||
assert.Len(t, groups, 2)
|
||||
|
||||
groups = SelectGroups(false, false)
|
||||
assert.Len(t, groups, 1)
|
||||
|
||||
groups = SelectGroups(false, true)
|
||||
assert.Len(t, groups, 2)
|
||||
|
||||
assert.Equal(t, "Updated", groups[0].Name)
|
||||
assert.Equal(t, "Example 2", groups[1].Name)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
package groups
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/services"
|
||||
)
|
||||
|
||||
func (g *Group) Services() []*services.Service {
|
||||
var services []*services.Service
|
||||
database.DB().Where("group = ?", g.Id).Find(&services)
|
||||
db.Where("group = ?", g.Id).Find(&services)
|
||||
return services
|
||||
}
|
||||
|
||||
|
|
|
@ -7,33 +7,35 @@ import (
|
|||
|
||||
var log = utils.Log
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Hit{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Hit{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Hit, error) {
|
||||
var group Hit
|
||||
db := DB().Where("id = ?", id).Find(&group)
|
||||
return &group, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&group)
|
||||
return &group, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Hit {
|
||||
var hits []*Hit
|
||||
DB().Find(&hits)
|
||||
db.Find(&hits)
|
||||
return hits
|
||||
}
|
||||
|
||||
func (h *Hit) Create() error {
|
||||
db := DB().Create(h)
|
||||
return db.Error()
|
||||
q := db.Create(h)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (h *Hit) Update() error {
|
||||
db := DB().Update(h)
|
||||
return db.Error()
|
||||
q := db.Update(h)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (h *Hit) Delete() error {
|
||||
db := DB().Delete(h)
|
||||
return db.Error()
|
||||
q := db.Delete(h)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ func (h Hitters) List() []*Hit {
|
|||
return hits
|
||||
}
|
||||
|
||||
func (h Hitters) LastCount(amounts int) []*Hit {
|
||||
func (h Hitters) LastAmount(amount int) []*Hit {
|
||||
var hits []*Hit
|
||||
h.db.Order("id asc").Limit(amounts).Find(&hits)
|
||||
h.db.Order("id asc").Limit(amount).Find(&hits)
|
||||
return hits
|
||||
}
|
||||
|
||||
|
@ -54,18 +54,23 @@ func (h Hitters) Count() int {
|
|||
return count
|
||||
}
|
||||
|
||||
func (h Hitters) DeleteAll() error {
|
||||
q := h.db.Delete(&Hit{})
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (h Hitters) Sum() float64 {
|
||||
result := struct {
|
||||
amount float64
|
||||
}{0}
|
||||
|
||||
h.db.Select("AVG(latency) as amount").Scan(&result).Debug()
|
||||
h.db.Select("AVG(latency) as amount").Scan(&result)
|
||||
return result.amount
|
||||
}
|
||||
|
||||
func (h Hitters) Avg() int64 {
|
||||
func (h Hitters) Avg() float64 {
|
||||
result := struct {
|
||||
amount int64
|
||||
amount float64
|
||||
}{0}
|
||||
|
||||
h.db.Select("AVG(latency) as amount").Scan(&result)
|
||||
|
@ -74,11 +79,11 @@ func (h Hitters) Avg() int64 {
|
|||
|
||||
func AllHits(obj ColumnIDInterfacer) Hitters {
|
||||
column, id := obj.HitsColumnID()
|
||||
return Hitters{DB().Where(fmt.Sprintf("%s = ?", column), id)}
|
||||
return Hitters{db.Where(fmt.Sprintf("%s = ?", column), id)}
|
||||
}
|
||||
|
||||
func HitsSince(t time.Time, obj ColumnIDInterfacer) Hitters {
|
||||
func Since(t time.Time, obj ColumnIDInterfacer) Hitters {
|
||||
column, id := obj.HitsColumnID()
|
||||
timestamp := DB().FormatTime(t)
|
||||
return Hitters{DB().Where(fmt.Sprintf("%s = ? AND created_at > ?", column), id, timestamp)}
|
||||
timestamp := db.FormatTime(t)
|
||||
return Hitters{db.Where(fmt.Sprintf("%s = ? AND created_at > ?", column), id, timestamp)}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
var SampleHits = 99900.
|
||||
|
||||
func Samples() error {
|
||||
tx := DB().Begin()
|
||||
tx := db.Begin()
|
||||
sg := new(sync.WaitGroup)
|
||||
|
||||
for i := int64(1); i <= 5; i++ {
|
||||
|
@ -24,7 +24,7 @@ func Samples() error {
|
|||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
tx = DB().Begin()
|
||||
tx = db.Begin()
|
||||
}
|
||||
|
||||
return tx.Error()
|
||||
|
@ -44,8 +44,8 @@ func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) err
|
|||
|
||||
hit := &Hit{
|
||||
Service: serviceID,
|
||||
Latency: latency,
|
||||
PingTime: latency * 0.15,
|
||||
Latency: int64(latency * 10000000),
|
||||
PingTime: int64(latency * 5000000),
|
||||
CreatedAt: createdAt,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ import "time"
|
|||
type Hit struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Service int64 `gorm:"column:service" json:"-"`
|
||||
Latency float64 `gorm:"column:latency" json:"latency"`
|
||||
PingTime float64 `gorm:"column:ping_time" json:"ping_time"`
|
||||
Latency int64 `gorm:"column:latency" json:"latency"`
|
||||
PingTime int64 `gorm:"column:ping_time" json:"ping_time"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
|
|
|
@ -2,29 +2,35 @@ package incidents
|
|||
|
||||
import "github.com/statping/statping/database"
|
||||
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Incident{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Incident, error) {
|
||||
var incident Incident
|
||||
db := database.DB().Model(&Incident{}).Where("id = ?", id).Find(&incident)
|
||||
return &incident, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&incident)
|
||||
return &incident, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Incident {
|
||||
var incidents []*Incident
|
||||
database.DB().Model(&Incident{}).Find(&incidents)
|
||||
db.Find(&incidents)
|
||||
return incidents
|
||||
}
|
||||
|
||||
func (i *Incident) Create() error {
|
||||
db := database.DB().Create(i)
|
||||
return db.Error()
|
||||
q := db.Create(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (i *Incident) Update() error {
|
||||
db := database.DB().Update(i)
|
||||
return db.Error()
|
||||
q := db.Update(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (i *Incident) Delete() error {
|
||||
db := database.DB().Delete(i)
|
||||
return db.Error()
|
||||
q := db.Delete(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -1,25 +1,23 @@
|
|||
package incidents
|
||||
|
||||
import "github.com/statping/statping/database"
|
||||
|
||||
func (i *Incident) Updates() []*IncidentUpdate {
|
||||
var updates []*IncidentUpdate
|
||||
database.DB().Model(&IncidentUpdate{}).Where("incident = ?", i.Id).Find(&updates)
|
||||
db.Model(&IncidentUpdate{}).Where("incident = ?", i.Id).Find(&updates)
|
||||
i.AllUpdates = updates
|
||||
return updates
|
||||
}
|
||||
|
||||
func (i *IncidentUpdate) Create() error {
|
||||
db := database.DB().Create(i)
|
||||
return db.Error()
|
||||
q := db.Create(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (i *IncidentUpdate) Update() error {
|
||||
db := database.DB().Update(i)
|
||||
return db.Error()
|
||||
q := db.Update(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (i *IncidentUpdate) Delete() error {
|
||||
db := database.DB().Delete(i)
|
||||
return db.Error()
|
||||
q := db.Delete(i)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package incidents
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var example = &Incident{
|
||||
Title: "Example",
|
||||
Description: "No description",
|
||||
ServiceId: 1,
|
||||
}
|
||||
|
||||
var update1 = &IncidentUpdate{
|
||||
IncidentId: 1,
|
||||
Message: "First one here",
|
||||
Type: "update",
|
||||
}
|
||||
|
||||
var update2 = &IncidentUpdate{
|
||||
IncidentId: 1,
|
||||
Message: "Second one here",
|
||||
Type: "update",
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.AutoMigrate(&Incident{}, &IncidentUpdate{})
|
||||
db.Create(&example)
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Example", item.Title)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &Incident{
|
||||
Title: "Example 2",
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "Example 2", example.Title)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Title = "Updated"
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated", item.Title)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -2,33 +2,35 @@ package messages
|
|||
|
||||
import "github.com/statping/statping/database"
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Message{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Message{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Message, error) {
|
||||
var message Message
|
||||
db := DB().Where("id = ?", id).Find(&message)
|
||||
return &message, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&message)
|
||||
return &message, q.Error()
|
||||
}
|
||||
|
||||
func All() []*Message {
|
||||
var messages []*Message
|
||||
DB().Find(&messages)
|
||||
db.Find(&messages)
|
||||
return messages
|
||||
}
|
||||
|
||||
func (m *Message) Create() error {
|
||||
db := DB().Create(m)
|
||||
return db.Error()
|
||||
q := db.Create(m)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (m *Message) Update() error {
|
||||
db := DB().Update(m)
|
||||
return db.Error()
|
||||
q := db.Update(m)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (m *Message) Delete() error {
|
||||
db := DB().Delete(m)
|
||||
return db.Error()
|
||||
q := db.Delete(m)
|
||||
return q.Error()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package messages
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var example = &Message{
|
||||
Title: "Example Message",
|
||||
Description: "Description here",
|
||||
StartOn: utils.Now().Add(10 * time.Minute),
|
||||
EndOn: utils.Now().Add(15 * time.Minute),
|
||||
ServiceId: 1,
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.CreateTable(&Message{})
|
||||
db.Create(&example)
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Example Message", item.Title)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &Message{
|
||||
Title: "Example 2",
|
||||
Description: "New Message here",
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "Example 2", example.Title)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Title = "Updated"
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated", item.Title)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -5,19 +5,21 @@ import (
|
|||
"github.com/statping/statping/database"
|
||||
)
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Notification{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Notification{})
|
||||
}
|
||||
|
||||
func Append(n Notifier) {
|
||||
allNotifiers = append(allNotifiers, n)
|
||||
}
|
||||
|
||||
func Find(name string) (Notifier, error) {
|
||||
func Find(name string) (*Notification, error) {
|
||||
for _, n := range allNotifiers {
|
||||
notif := n.Select()
|
||||
if notif.Name() == name || notif.Method == name {
|
||||
return n, nil
|
||||
return notif, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("notifier not found")
|
||||
|
@ -29,9 +31,11 @@ func All() []Notifier {
|
|||
|
||||
func (n *Notification) Create() error {
|
||||
var notif Notification
|
||||
if DB().Where("method = ?", n.Method).Find(¬if).RecordNotFound() {
|
||||
return DB().Create(n).Error()
|
||||
if db.Where("method = ?", n.Method).Find(¬if).RecordNotFound() {
|
||||
Append(n)
|
||||
return db.Create(n).Error()
|
||||
}
|
||||
Append(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -44,7 +48,7 @@ func (n *Notification) Update() error {
|
|||
} else {
|
||||
n.Close()
|
||||
}
|
||||
err := DB().Update(n)
|
||||
err := db.Update(n)
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var form1 = NotificationForm{
|
||||
Type: "text",
|
||||
Title: "Example Input",
|
||||
DbField: "Host",
|
||||
Required: true,
|
||||
IsHidden: false,
|
||||
IsList: false,
|
||||
IsSwitch: false,
|
||||
}
|
||||
|
||||
var form2 = NotificationForm{
|
||||
Type: "text",
|
||||
Title: "Example Input 2",
|
||||
DbField: "ApiKey",
|
||||
Required: true,
|
||||
IsHidden: false,
|
||||
IsList: false,
|
||||
IsSwitch: false,
|
||||
}
|
||||
|
||||
var example = &exampleNotif{&Notification{
|
||||
Method: "example",
|
||||
Enabled: null.NewNullBool(true),
|
||||
Limits: 3,
|
||||
Removable: false,
|
||||
Form: []NotificationForm{form1, form2},
|
||||
Delay: 30,
|
||||
}}
|
||||
|
||||
type exampleNotif struct {
|
||||
*Notification
|
||||
}
|
||||
|
||||
func (e *exampleNotif) OnSave() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *exampleNotif) Select() *Notification {
|
||||
return e.Notification
|
||||
}
|
||||
|
||||
func (e *exampleNotif) Send(data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.CreateTable(&Notification{})
|
||||
db.Create(example.Select())
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
Append(example)
|
||||
itemer, err := Find(example.Method)
|
||||
require.Nil(t, err)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
assert.Equal(t, "example", item.Method)
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
assert.Len(t, allNotifiers, 1)
|
||||
|
||||
example := &Notification{
|
||||
Method: "anotherexample",
|
||||
Title: "Example 2",
|
||||
Description: "New Message here",
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "anotherexample", example.Method)
|
||||
assert.Equal(t, "Example 2", example.Title)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
|
||||
items := All()
|
||||
assert.Len(t, items, 2)
|
||||
assert.Len(t, allNotifiers, 2)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
itemer, err := Find("anotherexample")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, itemer)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
item.Host = "Updated Host Var"
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Updated Host Var", item.Host)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
itemer, err := Find("example2")
|
||||
require.Nil(t, err)
|
||||
|
||||
item := itemer.Select()
|
||||
require.NotNil(t, item)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 2)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -152,7 +152,7 @@ func reverseLogs(input []*NotificationLog) []*NotificationLog {
|
|||
// SelectNotification returns the Notification struct from the database
|
||||
func SelectNotification(n Notifier) (*Notification, error) {
|
||||
notifier := n.Select()
|
||||
err := DB().Where("method = ?", notifier.Method).Find(¬ifier)
|
||||
err := db.Where("method = ?", notifier.Method).Find(¬ifier)
|
||||
return notifier, err.Error()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package null
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewNullBool(t *testing.T) {
|
||||
val := NewNullBool(true)
|
||||
assert.True(t, val.Bool)
|
||||
|
||||
val = NewNullBool(false)
|
||||
assert.False(t, val.Bool)
|
||||
}
|
||||
|
||||
func TestNewNullInt64(t *testing.T) {
|
||||
val := NewNullInt64(29)
|
||||
assert.Equal(t, int64(29), val.Int64)
|
||||
}
|
||||
|
||||
func TestNewNullString(t *testing.T) {
|
||||
val := NewNullString("statping.com")
|
||||
assert.Equal(t, "statping.com", val.String)
|
||||
}
|
||||
|
||||
func TestNewNullFloat64(t *testing.T) {
|
||||
val := NewNullFloat64(42.222)
|
||||
assert.Equal(t, float64(42.222), val.Float64)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
)
|
||||
|
||||
|
@ -15,6 +14,6 @@ func CheckinProcess(s *Service) {
|
|||
|
||||
func (s *Service) Checkins() []*checkins.Checkin {
|
||||
var chks []*checkins.Checkin
|
||||
database.DB().Where("service = ?", s.Id).Find(&chks)
|
||||
db.Where("service = ?", s.Id).Find(&chks)
|
||||
return chks
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@ import (
|
|||
|
||||
var log = utils.Log
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&Service{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Service{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*Service, error) {
|
||||
|
@ -24,7 +26,7 @@ func Find(id int64) (*Service, error) {
|
|||
|
||||
func all() []*Service {
|
||||
var services []*Service
|
||||
DB().Find(&services)
|
||||
db.Find(&services)
|
||||
return services
|
||||
}
|
||||
|
||||
|
@ -42,17 +44,21 @@ func AllInOrder() []Service {
|
|||
}
|
||||
|
||||
func (s *Service) Create() error {
|
||||
err := DB().Create(s)
|
||||
err := db.Create(s)
|
||||
if err.Error() != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to create service %v #%v: %v", s.Name, s.Id, err))
|
||||
return err.Error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) AfterCreate() error {
|
||||
allServices[s.Id] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Update() error {
|
||||
db := DB().Update(s)
|
||||
q := db.Update(s)
|
||||
|
||||
allServices[s.Id] = s
|
||||
|
||||
|
@ -68,20 +74,49 @@ func (s *Service) Update() error {
|
|||
|
||||
//notifier.OnUpdatedService(s.Service)
|
||||
|
||||
return db.Error()
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (s *Service) Delete() error {
|
||||
db := database.DB().Delete(s)
|
||||
|
||||
s.Close()
|
||||
delete(allServices, s.Id)
|
||||
//notifier.OnDeletedService(s.Service)
|
||||
|
||||
return db.Error()
|
||||
if err := s.DeleteFailures(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.DeleteHits(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(allServices, s.Id)
|
||||
|
||||
q := db.Model(&Service{}).Delete(s)
|
||||
//notifier.OnDeletedService(s.Service)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (s *Service) DeleteFailures() error {
|
||||
query := database.DB().Exec(`DELETE FROM failures WHERE service = ?`, s.Id)
|
||||
return query.Error()
|
||||
return s.AllFailures().DeleteAll()
|
||||
}
|
||||
|
||||
func (s *Service) DeleteHits() error {
|
||||
return s.AllHits().DeleteAll()
|
||||
}
|
||||
|
||||
func (s *Service) DeleteCheckins() error {
|
||||
for _, c := range s.Checkins() {
|
||||
if err := c.Delete(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//func (s *Service) AfterDelete() error {
|
||||
//
|
||||
// return nil
|
||||
//}
|
||||
|
||||
func (s *Service) AfterFind() error {
|
||||
s.UpdateStats()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,26 +15,13 @@ func (s *Service) AllFailures() failures.Failurer {
|
|||
return failures.AllFailures(s)
|
||||
}
|
||||
|
||||
func (s *Service) LastFailure() *failures.Failure {
|
||||
var fail failures.Failure
|
||||
failures.DB().Where("service = ?", s.Id).Order("id desc").Limit(1).Find(&fail)
|
||||
return &fail
|
||||
}
|
||||
|
||||
func (s *Service) FailuresCount() int {
|
||||
var amount int
|
||||
failures.DB().Where("service = ?", s.Id).Count(&amount)
|
||||
return amount
|
||||
}
|
||||
|
||||
func (s *Service) FailuresSince(t time.Time) []*failures.Failure {
|
||||
var fails []*failures.Failure
|
||||
failures.DB().Where("service = ?", s.Id).Find(&fails)
|
||||
func (s *Service) FailuresSince(t time.Time) failures.Failurer {
|
||||
fails := failures.Since(t, s)
|
||||
return fails
|
||||
}
|
||||
|
||||
func (s *Service) DowntimeText() string {
|
||||
last := s.LastFailure()
|
||||
last := s.AllFailures().Last()
|
||||
if last == nil {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ func (s *Service) AllHits() hits.Hitters {
|
|||
}
|
||||
|
||||
func (s *Service) HitsSince(t time.Time) hits.Hitters {
|
||||
return hits.HitsSince(t, s)
|
||||
return hits.Since(t, s)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/url"
|
||||
|
@ -33,6 +34,13 @@ func (s *Service) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
func humanMicro(val int64) string {
|
||||
if val < 10000 {
|
||||
return fmt.Sprintf("%d μs", val)
|
||||
}
|
||||
return fmt.Sprintf("%0.0f ms", float64(val)*0.001)
|
||||
}
|
||||
|
||||
// IsRunning returns true if the service go routine is running
|
||||
func (s *Service) IsRunning() bool {
|
||||
if s.Running == nil {
|
||||
|
@ -68,7 +76,7 @@ func SelectAllServices(start bool) (map[int64]*Service, error) {
|
|||
CheckinProcess(s)
|
||||
}
|
||||
|
||||
fails := s.AllFailures().Last(limitedFailures)
|
||||
fails := s.AllFailures().LastAmount(limitedFailures)
|
||||
s.Failures = fails
|
||||
|
||||
for _, c := range s.Checkins() {
|
||||
|
@ -137,12 +145,12 @@ func (s *Service) UpdateStats() *Service {
|
|||
s.Online24Hours = s.OnlineDaysPercent(1)
|
||||
s.Online7Days = s.OnlineDaysPercent(7)
|
||||
s.AvgResponse = s.AvgTime()
|
||||
s.FailuresLast24Hours = len(s.AllFailures().Since(utils.Now().Add(-time.Hour * 24)))
|
||||
s.FailuresLast24Hours = s.FailuresSince(utils.Now().Add(-time.Hour * 24)).Count()
|
||||
|
||||
if s.LastOffline.IsZero() {
|
||||
lastFail := s.LastFailure()
|
||||
lastFail := s.AllFailures().Last()
|
||||
if lastFail != nil {
|
||||
s.LastOffline = s.LastFailure().CreatedAt
|
||||
s.LastOffline = lastFail.CreatedAt
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,29 +163,31 @@ func (s *Service) UpdateStats() *Service {
|
|||
}
|
||||
|
||||
// AvgTime will return the average amount of time for a service to response back successfully
|
||||
func (s *Service) AvgTime() int64 {
|
||||
func (s *Service) AvgTime() float64 {
|
||||
return s.AllHits().Avg()
|
||||
}
|
||||
|
||||
// OnlineDaysPercent returns the service's uptime percent within last 24 hours
|
||||
func (s *Service) OnlineDaysPercent(days int) float32 {
|
||||
ago := utils.Now().Add((-24 * time.Duration(days)) * time.Hour)
|
||||
ago := utils.Now().Add(-time.Duration(days) * types.Day)
|
||||
return s.OnlineSince(ago)
|
||||
}
|
||||
|
||||
// OnlineSince accepts a time since parameter to return the percent of a service's uptime.
|
||||
func (s *Service) OnlineSince(ago time.Time) float32 {
|
||||
failed := s.AllFailures().Since(ago)
|
||||
if len(failed) == 0 {
|
||||
failed := s.FailuresSince(ago)
|
||||
failsList := failed.List()
|
||||
if len(failsList) == 0 {
|
||||
s.Online24Hours = 100.00
|
||||
return s.Online24Hours
|
||||
}
|
||||
total := s.AllHits().Since(ago)
|
||||
if len(total) == 0 {
|
||||
total := s.HitsSince(ago)
|
||||
hitsList := total.List()
|
||||
if len(hitsList) == 0 {
|
||||
s.Online24Hours = 0
|
||||
return s.Online24Hours
|
||||
}
|
||||
avg := float64(len(failed)) / float64(len(total)) * 100
|
||||
avg := float64(len(hitsList)) / float64(len(failsList)) * 100
|
||||
avg = 100 - avg
|
||||
if avg < 0 {
|
||||
avg = 0
|
||||
|
@ -190,12 +200,12 @@ func (s *Service) OnlineSince(ago time.Time) float32 {
|
|||
// Downtime returns the amount of time of a offline service
|
||||
func (s *Service) Downtime() time.Duration {
|
||||
hit := s.LastHit()
|
||||
fail := s.LastFailure()
|
||||
fail := s.AllFailures().Last()
|
||||
if hit == nil {
|
||||
return time.Duration(0)
|
||||
}
|
||||
if fail == nil {
|
||||
return utils.Now().Sub(fail.CreatedAt)
|
||||
return utils.Now().Sub(hit.CreatedAt)
|
||||
}
|
||||
|
||||
return fail.CreatedAt.Sub(hit.CreatedAt)
|
||||
|
|
|
@ -64,9 +64,9 @@ func parseHost(s *Service) string {
|
|||
}
|
||||
|
||||
// dnsCheck will check the domain name and return a float64 for the amount of time the DNS check took
|
||||
func dnsCheck(s *Service) (float64, error) {
|
||||
func dnsCheck(s *Service) (int64, error) {
|
||||
var err error
|
||||
t1 := time.Now()
|
||||
t1 := utils.Now()
|
||||
host := parseHost(s)
|
||||
if s.Type == "tcp" {
|
||||
_, err = net.LookupHost(host)
|
||||
|
@ -77,7 +77,7 @@ func dnsCheck(s *Service) (float64, error) {
|
|||
return 0, err
|
||||
}
|
||||
t2 := time.Now()
|
||||
subTime := t2.Sub(t1).Seconds()
|
||||
subTime := t2.Sub(t1).Microseconds()
|
||||
return subTime, err
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ func CheckIcmp(s *Service, record bool) *Service {
|
|||
}
|
||||
p.AddIPAddr(ra)
|
||||
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
|
||||
s.Latency = rtt.Seconds()
|
||||
s.Latency = rtt.Microseconds()
|
||||
recordSuccess(s)
|
||||
}
|
||||
err = p.Run()
|
||||
|
@ -125,7 +125,7 @@ func CheckTcp(s *Service, record bool) *Service {
|
|||
return s
|
||||
}
|
||||
s.PingTime = dnsLookup
|
||||
t1 := time.Now()
|
||||
t1 := utils.Now()
|
||||
domain := fmt.Sprintf("%v", s.Domain)
|
||||
if s.Port != 0 {
|
||||
domain = fmt.Sprintf("%v:%v", s.Domain, s.Port)
|
||||
|
@ -146,8 +146,8 @@ func CheckTcp(s *Service, record bool) *Service {
|
|||
}
|
||||
return s
|
||||
}
|
||||
t2 := time.Now()
|
||||
s.Latency = t2.Sub(t1).Seconds()
|
||||
t2 := utils.Now()
|
||||
s.Latency = t2.Sub(t1).Microseconds()
|
||||
s.LastResponse = ""
|
||||
if record {
|
||||
recordSuccess(s)
|
||||
|
@ -171,7 +171,7 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
return s
|
||||
}
|
||||
s.PingTime = dnsLookup
|
||||
t1 := time.Now()
|
||||
t1 := utils.Now()
|
||||
|
||||
timeout := time.Duration(s.Timeout) * time.Second
|
||||
var content []byte
|
||||
|
@ -195,8 +195,8 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
}
|
||||
return s
|
||||
}
|
||||
t2 := time.Now()
|
||||
s.Latency = t2.Sub(t1).Seconds()
|
||||
t2 := utils.Now()
|
||||
s.Latency = t2.Sub(t1).Microseconds()
|
||||
s.LastResponse = string(content)
|
||||
s.LastStatusCode = res.StatusCode
|
||||
|
||||
|
@ -226,21 +226,21 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
|
||||
// recordSuccess will create a new 'hit' record in the database for a successful/online service
|
||||
func recordSuccess(s *Service) {
|
||||
s.LastOnline = time.Now().UTC()
|
||||
s.LastOnline = utils.Now()
|
||||
s.Online = true
|
||||
hit := &hits.Hit{
|
||||
Service: s.Id,
|
||||
Latency: s.Latency,
|
||||
PingTime: s.PingTime,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
CreatedAt: utils.Now(),
|
||||
}
|
||||
if err := hit.Create(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
log.WithFields(utils.ToFields(hit, s)).Infoln(
|
||||
fmt.Sprintf("Service #%d '%v' Successful Response: %0.2f ms | Lookup in: %0.2f ms | Online: %v | Interval: %d seconds", s.Id, s.Name, hit.Latency*1000, hit.PingTime*1000, s.Online, s.Interval))
|
||||
s.LastLookupTime = int64(hit.PingTime * 1000)
|
||||
s.LastLatency = int64(hit.Latency * 1000)
|
||||
fmt.Sprintf("Service #%d '%v' Successful Response: %s | Lookup in: %s | Online: %v | Interval: %d seconds", s.Id, s.Name, humanMicro(hit.Latency), humanMicro(hit.PingTime), s.Online, s.Interval))
|
||||
s.LastLookupTime = hit.PingTime
|
||||
s.LastLatency = hit.Latency
|
||||
//notifier.OnSuccess(s)
|
||||
s.SuccessNotified = true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var example = &Service{
|
||||
Name: "Example Service",
|
||||
Domain: "https://statping.com",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 30,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 5,
|
||||
Order: 1,
|
||||
VerifySSL: null.NewNullBool(true),
|
||||
Public: null.NewNullBool(true),
|
||||
GroupId: 1,
|
||||
Permalink: null.NewNullString("statping"),
|
||||
LastCheck: utils.Now().Add(-5 * time.Second),
|
||||
LastOffline: utils.Now().Add(-5 * time.Second),
|
||||
LastOnline: utils.Now().Add(-60 * time.Second),
|
||||
}
|
||||
|
||||
var hit1 = &hits.Hit{
|
||||
Service: 1,
|
||||
Latency: 0.1234,
|
||||
PingTime: 0.01234,
|
||||
CreatedAt: utils.Now().Add(-120 * time.Second),
|
||||
}
|
||||
|
||||
var hit2 = &hits.Hit{
|
||||
Service: 1,
|
||||
Latency: 0.2345,
|
||||
PingTime: 0.02345,
|
||||
CreatedAt: utils.Now().Add(-60 * time.Second),
|
||||
}
|
||||
|
||||
var hit3 = &hits.Hit{
|
||||
Service: 1,
|
||||
Latency: 0.3456,
|
||||
PingTime: 0.03456,
|
||||
CreatedAt: utils.Now().Add(-30 * time.Second),
|
||||
}
|
||||
|
||||
var exmapleCheckin = &checkins.Checkin{
|
||||
ServiceId: 1,
|
||||
Name: "Example Checkin",
|
||||
Interval: 60,
|
||||
GracePeriod: 30,
|
||||
ApiKey: "wdededede",
|
||||
}
|
||||
|
||||
var fail1 = &failures.Failure{
|
||||
Issue: "example not found",
|
||||
ErrorCode: 404,
|
||||
Service: 1,
|
||||
PingTime: 0.0123,
|
||||
CreatedAt: utils.Now().Add(-160 * time.Second),
|
||||
}
|
||||
|
||||
var fail2 = &failures.Failure{
|
||||
Issue: "example 2 not found",
|
||||
ErrorCode: 500,
|
||||
Service: 1,
|
||||
PingTime: 0.0123,
|
||||
CreatedAt: utils.Now().Add(-5 * time.Second),
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.AutoMigrate(&Service{}, &hits.Hit{}, &checkins.Checkin{}, &checkins.CheckinHit{}, &failures.Failure{})
|
||||
db.Create(&example)
|
||||
db.Create(&hit1)
|
||||
db.Create(&hit2)
|
||||
db.Create(&hit3)
|
||||
db.Create(&exmapleCheckin)
|
||||
db.Create(&fail1)
|
||||
db.Create(&fail2)
|
||||
checkins.SetDB(db)
|
||||
failures.SetDB(db)
|
||||
hits.SetDB(db)
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "Example Service", item.Name)
|
||||
assert.NotZero(t, item.LastOnline)
|
||||
assert.NotZero(t, item.LastOffline)
|
||||
assert.NotZero(t, item.LastCheck)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestService_Checkins(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, item.Checkins(), 1)
|
||||
}
|
||||
|
||||
func TestService_AllHits(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, item.AllHits().List(), 3)
|
||||
assert.Equal(t, 3, item.AllHits().Count())
|
||||
}
|
||||
|
||||
func TestService_AllFailures(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, item.AllFailures().List(), 2)
|
||||
assert.Equal(t, 2, item.AllFailures().Count())
|
||||
}
|
||||
|
||||
func TestService_FirstHit(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
hit := item.FirstHit()
|
||||
assert.Equal(t, int64(1), hit.Id)
|
||||
}
|
||||
|
||||
func TestService_LastHit(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
hit := item.AllHits().Last()
|
||||
assert.Equal(t, int64(3), hit.Id)
|
||||
}
|
||||
|
||||
func TestService_LastFailure(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
fail := item.AllFailures().Last()
|
||||
assert.Equal(t, int64(2), fail.Id)
|
||||
}
|
||||
|
||||
func TestService_Duration(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, float64(30), item.Duration().Seconds())
|
||||
}
|
||||
|
||||
func TestService_AvgTime(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.Equal(t, "", item.AvgTime())
|
||||
}
|
||||
|
||||
func TestService_HitsSince(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
count := item.HitsSince(utils.Now().Add(-30 * time.Second))
|
||||
assert.Equal(t, 1, count.Count())
|
||||
|
||||
count = item.HitsSince(utils.Now().Add(-180 * time.Second))
|
||||
assert.Equal(t, 3, count.Count())
|
||||
}
|
||||
|
||||
func TestService_IsRunning(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.False(t, item.IsRunning())
|
||||
}
|
||||
|
||||
func TestService_OnlineDaysPercent(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
amount := item.OnlineDaysPercent(1)
|
||||
|
||||
assert.Equal(t, "", amount)
|
||||
}
|
||||
|
||||
func TestService_Downtime(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
amount := item.Downtime().Seconds()
|
||||
assert.Equal(t, "25", fmt.Sprintf("%0.f", amount))
|
||||
}
|
||||
|
||||
func TestService_FailuresSince(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
count := item.FailuresSince(utils.Now().Add(-6 * time.Second))
|
||||
assert.Equal(t, 1, count.Count())
|
||||
|
||||
count = item.FailuresSince(utils.Now().Add(-180 * time.Second))
|
||||
assert.Equal(t, 2, count.Count())
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &Service{
|
||||
Name: "Example Service 2",
|
||||
Domain: "https://slack.statping.com",
|
||||
ExpectedStatus: 200,
|
||||
Interval: 10,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 5,
|
||||
Order: 3,
|
||||
VerifySSL: null.NewNullBool(true),
|
||||
Public: null.NewNullBool(false),
|
||||
GroupId: 1,
|
||||
Permalink: null.NewNullString("statping2"),
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "Example Service 2", example.Name)
|
||||
assert.False(t, example.Public.Bool)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
assert.Equal(t, int64(2), example.Id)
|
||||
assert.Len(t, allServices, 2)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Name = "Updated Service"
|
||||
item.Order = 1
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, int64(1), item.Id)
|
||||
assert.Equal(t, "Updated Service", item.Name)
|
||||
}
|
||||
|
||||
func TestAllInOrder(t *testing.T) {
|
||||
inOrder := AllInOrder()
|
||||
assert.Len(t, inOrder, 2)
|
||||
assert.Equal(t, "Updated Service", inOrder[0].Name)
|
||||
assert.Equal(t, "Example Service 2", inOrder[1].Name)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, int64(1), item.Id)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestService_CheckService(t *testing.T) {
|
||||
item, err := Find(2)
|
||||
require.Nil(t, err)
|
||||
|
||||
hitsCount := item.AllHits().Count()
|
||||
failsCount := item.AllFailures().Count()
|
||||
|
||||
assert.Equal(t, 3, hitsCount)
|
||||
assert.Equal(t, 2, failsCount)
|
||||
|
||||
item.CheckService(true)
|
||||
|
||||
assert.Equal(t, 4, hitsCount)
|
||||
assert.Equal(t, 2, failsCount)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
|
@ -41,11 +41,11 @@ type Service struct {
|
|||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Online bool `gorm:"-" json:"online"`
|
||||
Latency float64 `gorm:"-" json:"latency"`
|
||||
PingTime float64 `gorm:"-" json:"ping_time"`
|
||||
Latency int64 `gorm:"-" json:"latency"`
|
||||
PingTime int64 `gorm:"-" json:"ping_time"`
|
||||
Online24Hours float32 `gorm:"-" json:"online_24_hours"`
|
||||
Online7Days float32 `gorm:"-" json:"online_7_days"`
|
||||
AvgResponse int64 `gorm:"-" json:"avg_response"`
|
||||
AvgResponse float64 `gorm:"-" json:"avg_response"`
|
||||
FailuresLast24Hours int `gorm:"-" json:"failures_24_hours"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
Checkpoint time.Time `gorm:"-" json:"-"`
|
||||
|
|
|
@ -4,56 +4,56 @@ import (
|
|||
"github.com/prometheus/common/log"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
func DB() database.Database {
|
||||
return database.DB().Model(&User{})
|
||||
var db database.Database
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&User{})
|
||||
}
|
||||
|
||||
func Find(id int64) (*User, error) {
|
||||
var user User
|
||||
db := DB().Where("id = ?", id).Find(&user)
|
||||
return &user, db.Error()
|
||||
q := db.Where("id = ?", id).Find(&user)
|
||||
return &user, q.Error()
|
||||
}
|
||||
|
||||
func FindByUsername(username string) (*User, error) {
|
||||
var user User
|
||||
db := DB().Where("username = ?", username).Find(&user)
|
||||
return &user, db.Error()
|
||||
q := db.Where("username = ?", username).Find(&user)
|
||||
return &user, q.Error()
|
||||
}
|
||||
|
||||
func All() []*User {
|
||||
var users []*User
|
||||
DB().Find(&users)
|
||||
db.Find(&users)
|
||||
return users
|
||||
}
|
||||
|
||||
func (u *User) Create() error {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
u.Password = utils.HashPassword(u.Password)
|
||||
if u.ApiKey == "" || u.ApiSecret == "" {
|
||||
u.ApiKey = utils.NewSHA1Hash(16)
|
||||
u.ApiSecret = utils.NewSHA1Hash(16)
|
||||
}
|
||||
db := DB().Create(u)
|
||||
q := db.Create(u)
|
||||
if db.Error() == nil {
|
||||
log.Warnf("User #%d (%s) has been created", u.Id, u.Username)
|
||||
}
|
||||
return db.Error()
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (u *User) Update() error {
|
||||
//u.ApiKey = utils.NewSHA1Hash(5)
|
||||
//u.ApiSecret = utils.NewSHA1Hash(10)
|
||||
db := DB().Update(u)
|
||||
return db.Error()
|
||||
q := db.Update(u)
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (u *User) Delete() error {
|
||||
db := DB().Delete(u)
|
||||
q := db.Delete(u)
|
||||
if db.Error() == nil {
|
||||
log.Warnf("User #%d (%s) has been deleted", u.Id, u.Username)
|
||||
}
|
||||
return db.Error()
|
||||
return q.Error()
|
||||
}
|
||||
|
||||
func (u *User) BeforeCreate() error {
|
||||
u.Password = utils.HashPassword(u.Password)
|
||||
u.ApiKey = utils.NewSHA1Hash(16)
|
||||
u.ApiSecret = utils.NewSHA1Hash(16)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package users
|
|||
|
||||
import (
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/statping/statping/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -18,14 +17,3 @@ type User struct {
|
|||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
// BeforeCreate for User will set CreatedAt to UTC
|
||||
func (u *User) BeforeCreate() (err error) {
|
||||
u.ApiKey = utils.RandomString(16)
|
||||
u.ApiSecret = utils.RandomString(16)
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
u.UpdatedAt = time.Now().UTC()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package users
|
||||
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/null"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var example = &User{
|
||||
Username: "example_user",
|
||||
Email: "Description here",
|
||||
Password: "password123",
|
||||
Admin: null.NewNullBool(true),
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.CreateTable(&User{})
|
||||
db.Create(&example)
|
||||
SetDB(db)
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "example_user", item.Username)
|
||||
assert.NotEmpty(t, item.ApiKey)
|
||||
assert.NotEmpty(t, item.ApiSecret)
|
||||
assert.NotEqual(t, "password123", item.Password)
|
||||
assert.True(t, item.Admin.Bool)
|
||||
}
|
||||
|
||||
func TestFindByUsername(t *testing.T) {
|
||||
item, err := FindByUsername("example_user")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "example_user", item.Username)
|
||||
assert.NotEmpty(t, item.ApiKey)
|
||||
assert.NotEmpty(t, item.ApiSecret)
|
||||
assert.NotEqual(t, "password123", item.Password)
|
||||
assert.True(t, item.Admin.Bool)
|
||||
}
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
example := &User{
|
||||
Username: "exampleuser2",
|
||||
Password: "password12345",
|
||||
Email: "info@yahoo.com",
|
||||
}
|
||||
err := example.Create()
|
||||
require.Nil(t, err)
|
||||
assert.NotZero(t, example.Id)
|
||||
assert.Equal(t, "exampleuser2", example.Username)
|
||||
assert.NotEqual(t, "password12345", example.Password)
|
||||
assert.NotZero(t, example.CreatedAt)
|
||||
assert.NotEmpty(t, example.ApiKey)
|
||||
assert.NotEmpty(t, example.ApiSecret)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
item.Username = "updated_user"
|
||||
err = item.Update()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "updated_user", item.Username)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
all := All()
|
||||
assert.Len(t, all, 2)
|
||||
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
err = item.Delete()
|
||||
require.Nil(t, err)
|
||||
|
||||
all = All()
|
||||
assert.Len(t, all, 1)
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
assert.Nil(t, db.Close())
|
||||
}
|
Loading…
Reference in New Issue