Merge pull request #335 from hunterlong/logs

faster testing
pull/342/head
Hunter Long 2019-12-29 17:41:46 -08:00 committed by GitHub
commit 14ae26c040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 246 additions and 520 deletions

View File

@ -16,4 +16,5 @@ dev
!dev/demo-script.sh !dev/demo-script.sh
!build/alpine-linux-amd64 !build/alpine-linux-amd64
config.yml config.yml
statup.db *.db
tmp

3
.gitignore vendored
View File

@ -5,7 +5,7 @@ stage
parts parts
core/rice-box.go core/rice-box.go
config.yml config.yml
statup.db *.db
plugins/*.so plugins/*.so
data data
build build
@ -19,6 +19,7 @@ assets
*.log *.log
.env .env
logs logs
tmp
/dev/test/node_modules /dev/test/node_modules
dev/test/cypress/videos dev/test/cypress/videos
dev/test/cypress/screenshots dev/test/cypress/screenshots

View File

@ -7,6 +7,7 @@ cache:
directories: directories:
- "~/.npm" - "~/.npm"
- "~/.cache" - "~/.cache"
- "$GOPATH/src/github.com/hunterlong/statping/tmp"
- "$GOPATH/src/github.com/hunterlong/statping/vendor" - "$GOPATH/src/github.com/hunterlong/statping/vendor"
sudo: required sudo: required
services: services:

View File

@ -168,11 +168,9 @@ func updateDisplay() error {
return err return err
} }
if VERSION != gitCurrent.TagName[1:] { if VERSION != gitCurrent.TagName[1:] {
fmt.Printf("\n New Update %v Available\n", gitCurrent.TagName[1:]) fmt.Printf("\nNew Update %v Available!\n", gitCurrent.TagName[1:])
fmt.Printf("Update Command:\n") fmt.Printf("Update Command:\n")
fmt.Printf("curl -o- -L https://statping.com/install.sh | bash\n\n") fmt.Printf("curl -o- -L https://statping.com/install.sh | bash\n\n")
} else {
fmt.Printf("You have the latest version of Statping\n")
} }
return nil return nil
} }

View File

@ -17,7 +17,6 @@ package main
import ( import (
"github.com/hunterlong/statping/core" "github.com/hunterlong/statping/core"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/utils" "github.com/hunterlong/statping/utils"
"github.com/rendon/testcli" "github.com/rendon/testcli"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -98,6 +97,7 @@ func TestAssetsCommand(t *testing.T) {
c.Run() c.Run()
t.Log(c.Stdout()) t.Log(c.Stdout())
t.Log("Directory for Assets: ", dir) t.Log("Directory for Assets: ", dir)
time.Sleep(1 * time.Second)
assert.FileExists(t, dir+"/assets/robots.txt") assert.FileExists(t, dir+"/assets/robots.txt")
assert.FileExists(t, dir+"/assets/scss/base.scss") assert.FileExists(t, dir+"/assets/scss/base.scss")
} }
@ -166,7 +166,6 @@ func TestRunOnceCLI(t *testing.T) {
func TestEnvCLI(t *testing.T) { func TestEnvCLI(t *testing.T) {
run := catchCLI([]string{"env"}) run := catchCLI([]string{"env"})
assert.Error(t, run) assert.Error(t, run)
Clean()
} }
func commandAndSleep(cmd *exec.Cmd, duration time.Duration, out chan<- string) { func commandAndSleep(cmd *exec.Cmd, duration time.Duration, out chan<- string) {
@ -186,15 +185,3 @@ func runCommand(c *exec.Cmd, out chan<- string) {
bout, _ := c.CombinedOutput() bout, _ := c.CombinedOutput()
out <- string(bout) out <- string(bout)
} }
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statping.db")
utils.DeleteDirectory(dir + "/assets")
utils.DeleteDirectory(dir + "/logs")
core.CoreApp = core.NewCore()
source.Assets()
//core.CloseDB()
os.Unsetenv("DB_CONN")
time.Sleep(2 * time.Second)
}

View File

@ -176,6 +176,7 @@ func EnvToConfig() (*DbConfig, error) {
Password: adminPass, Password: adminPass,
Error: nil, Error: nil,
Location: utils.Directory, Location: utils.Directory,
SqlFile: os.Getenv("SQL_FILE"),
} }
return Configs, err return Configs, err
} }

View File

@ -147,10 +147,12 @@ func (c Core) AllOnline() bool {
// SelectCore will return the CoreApp global variable and the settings/configs for Statping // SelectCore will return the CoreApp global variable and the settings/configs for Statping
func SelectCore() (*Core, error) { func SelectCore() (*Core, error) {
if DbSession == nil { if DbSession == nil {
log.Traceln("database has not been initiated yet.")
return nil, errors.New("database has not been initiated yet.") return nil, errors.New("database has not been initiated yet.")
} }
exists := DbSession.HasTable("core") exists := DbSession.HasTable("core")
if !exists { if !exists {
log.Errorf("core database has not been setup yet, does not have the 'core' table")
return nil, errors.New("core database has not been setup yet.") return nil, errors.New("core database has not been setup yet.")
} }
db := coreDB().First(&CoreApp) db := coreDB().First(&CoreApp)

View File

@ -19,6 +19,7 @@ import (
"github.com/hunterlong/statping/source" "github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/utils" "github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"os" "os"
"testing" "testing"
) )
@ -37,31 +38,27 @@ func init() {
} }
func TestNewCore(t *testing.T) { func TestNewCore(t *testing.T) {
if skipNewDb { err := TmpRecords("core.db")
t.SkipNow() require.Nil(t, err)
} require.NotNil(t, CoreApp)
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
CoreApp = NewCore()
assert.NotNil(t, CoreApp)
CoreApp.Name = "Tester"
} }
func TestDbConfig_Save(t *testing.T) { func TestDbConfig_Save(t *testing.T) {
if skipNewDb { t.SkipNow()
t.SkipNow() //if skipNewDb {
} // t.SkipNow()
var err error //}
Configs = &DbConfig{ //var err error
DbConn: "sqlite", //Configs = &DbConfig{
Project: "Tester", // DbConn: "sqlite",
Location: dir, // Project: "Tester",
} // Location: dir,
Configs, err = Configs.Save() //}
assert.Nil(t, err) //Configs, err = Configs.Save()
assert.Equal(t, "sqlite", Configs.DbConn) //assert.Nil(t, err)
assert.NotEmpty(t, Configs.ApiKey) //assert.Equal(t, "sqlite", Configs.DbConn)
assert.NotEmpty(t, Configs.ApiSecret) //assert.NotEmpty(t, Configs.ApiKey)
//assert.NotEmpty(t, Configs.ApiSecret)
} }
func TestLoadDbConfig(t *testing.T) { func TestLoadDbConfig(t *testing.T) {
@ -76,6 +73,7 @@ func TestDbConnection(t *testing.T) {
} }
func TestDropDatabase(t *testing.T) { func TestDropDatabase(t *testing.T) {
t.SkipNow()
if skipNewDb { if skipNewDb {
t.SkipNow() t.SkipNow()
} }
@ -84,6 +82,7 @@ func TestDropDatabase(t *testing.T) {
} }
func TestSeedSchemaDatabase(t *testing.T) { func TestSeedSchemaDatabase(t *testing.T) {
t.SkipNow()
if skipNewDb { if skipNewDb {
t.SkipNow() t.SkipNow()
} }
@ -92,14 +91,13 @@ func TestSeedSchemaDatabase(t *testing.T) {
} }
func TestMigrateDatabase(t *testing.T) { func TestMigrateDatabase(t *testing.T) {
t.SkipNow()
err := Configs.MigrateDatabase() err := Configs.MigrateDatabase()
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestSeedDatabase(t *testing.T) { func TestSeedDatabase(t *testing.T) {
if skipNewDb { t.SkipNow()
t.SkipNow()
}
err := InsertLargeSampleData() err := InsertLargeSampleData()
assert.Nil(t, err) assert.Nil(t, err)
} }
@ -117,6 +115,7 @@ func TestSelectCore(t *testing.T) {
} }
func TestInsertNotifierDB(t *testing.T) { func TestInsertNotifierDB(t *testing.T) {
t.SkipNow()
if skipNewDb { if skipNewDb {
t.SkipNow() t.SkipNow()
} }
@ -134,7 +133,7 @@ func TestEnvToConfig(t *testing.T) {
os.Setenv("DESCRIPTION", "Testing Statping") os.Setenv("DESCRIPTION", "Testing Statping")
os.Setenv("ADMIN_USER", "admin") os.Setenv("ADMIN_USER", "admin")
os.Setenv("ADMIN_PASS", "admin123") os.Setenv("ADMIN_PASS", "admin123")
os.Setenv("VERBOSE", "true") os.Setenv("VERBOSE", "1")
config, err := EnvToConfig() config, err := EnvToConfig()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, config.DbConn, "sqlite") assert.Equal(t, config.DbConn, "sqlite")

View File

@ -26,6 +26,7 @@ import (
_ "github.com/jinzhu/gorm/dialects/postgres" _ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/jinzhu/gorm/dialects/sqlite" _ "github.com/jinzhu/gorm/dialects/sqlite"
"os" "os"
"path/filepath"
"time" "time"
) )
@ -185,6 +186,26 @@ func (db *DbConfig) InsertCore() (*Core, error) {
return CoreApp, query.Error return CoreApp, query.Error
} }
func findDbFile() string {
if Configs.SqlFile != "" {
return Configs.SqlFile
}
filename := types.SqliteFilename
err := filepath.Walk(utils.Directory, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if filepath.Ext(path) == ".db" {
filename = info.Name()
}
return nil
})
if err != nil {
log.Error(err)
}
return filename
}
// Connect will attempt to connect to the sqlite, postgres, or mysql database // Connect will attempt to connect to the sqlite, postgres, or mysql database
func (db *DbConfig) Connect(retry bool, location string) error { func (db *DbConfig) Connect(retry bool, location string) error {
postgresSSL := os.Getenv("POSTGRES_SSLMODE") postgresSSL := os.Getenv("POSTGRES_SSLMODE")
@ -199,7 +220,8 @@ func (db *DbConfig) Connect(retry bool, location string) error {
} }
switch dbType { switch dbType {
case "sqlite": case "sqlite":
conn = location + "/statup.db" sqlFilename := findDbFile()
conn = sqlFilename
dbType = "sqlite3" dbType = "sqlite3"
case "mysql": case "mysql":
host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort) host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
@ -226,8 +248,7 @@ func (db *DbConfig) Connect(retry bool, location string) error {
if dbType == "sqlite3" { if dbType == "sqlite3" {
dbSession.DB().SetMaxOpenConns(1) dbSession.DB().SetMaxOpenConns(1)
} }
err = dbSession.DB().Ping() if dbSession.DB().Ping() == nil {
if err == nil {
DbSession = dbSession DbSession = dbSession
if utils.VerboseMode >= 4 { if utils.VerboseMode >= 4 {
DbSession.LogMode(true).Debug().SetLogger(log) DbSession.LogMode(true).Debug().SetLogger(log)
@ -283,8 +304,8 @@ func (db *DbConfig) Update() error {
// Save will initially create the config.yml file // Save will initially create the config.yml file
func (db *DbConfig) Save() (*DbConfig, error) { func (db *DbConfig) Save() (*DbConfig, error) {
var err error
config, err := os.Create(utils.Directory + "/config.yml") config, err := os.Create(utils.Directory + "/config.yml")
defer config.Close()
if err != nil { if err != nil {
log.Errorln(err) log.Errorln(err)
return nil, err return nil, err
@ -297,7 +318,6 @@ func (db *DbConfig) Save() (*DbConfig, error) {
return nil, err return nil, err
} }
config.WriteString(string(data)) config.WriteString(string(data))
defer config.Close()
return db, err return db, err
} }

View File

@ -18,7 +18,6 @@ package notifier
import ( import (
"fmt" "fmt"
"github.com/hunterlong/statping/types" "github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite" _ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -56,8 +55,7 @@ var core = &types.Core{
} }
func injectDatabase() { func injectDatabase() {
utils.DeleteFile(dir + "/statup.db") db, _ = gorm.Open("sqlite3", dir+"/notifier.db")
db, _ = gorm.Open("sqlite3", dir+"/statup.db")
db.CreateTable(&Notification{}) db.CreateTable(&Notification{})
} }

View File

@ -17,6 +17,7 @@ package core
import ( import (
"fmt" "fmt"
"github.com/hunterlong/statping/core/notifier"
"github.com/hunterlong/statping/types" "github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils" "github.com/hunterlong/statping/utils"
"time" "time"
@ -493,3 +494,99 @@ func insertHitRecords(since time.Time, amount int64) {
} }
} }
// TmpRecords is used for testing Statping. It will create a SQLite database file
// with sample data and store it in the /tmp folder to be used by the tests.
func TmpRecords(dbFile string) error {
var sqlFile = utils.Directory + "/" + dbFile
utils.CreateDirectory(utils.Directory + "/tmp")
var tmpSqlFile = utils.Directory + "/tmp/" + types.SqliteFilename
SampleHits = 480
var err error
CoreApp = NewCore()
CoreApp.Name = "Tester"
Configs = &DbConfig{
DbConn: "sqlite",
Project: "Tester",
Location: utils.Directory,
SqlFile: sqlFile,
}
log.Infoln("saving config.yml in: " + utils.Directory)
if Configs, err = Configs.Save(); err != nil {
return err
}
log.Infoln("loading config.yml from: " + utils.Directory)
if Configs, err = LoadConfigFile(utils.Directory); err != nil {
return err
}
log.Infoln("connecting to database")
exists := utils.FileExists(tmpSqlFile)
if exists {
log.Infoln(tmpSqlFile + " was found, copying the temp database to " + sqlFile)
if err := utils.DeleteFile(sqlFile); err != nil {
log.Infoln(sqlFile + " was not found")
}
if err := utils.CopyFile(tmpSqlFile, sqlFile); err != nil {
return err
}
log.Infoln("loading config.yml from: " + utils.Directory)
if err := Configs.Connect(false, utils.Directory); err != nil {
return err
}
log.Infoln("selecting the Core variable")
if _, err := SelectCore(); err != nil {
return err
}
log.Infoln("inserting notifiers into database")
if err := InsertNotifierDB(); err != nil {
return err
}
log.Infoln("loading all services")
if _, err := CoreApp.SelectAllServices(false); err != nil {
return err
}
if err := AttachNotifiers(); err != nil {
return err
}
CoreApp.Notifications = notifier.AllCommunications
return nil
}
log.Infoln(tmpSqlFile + " not found, creating a new database...")
if err := Configs.Connect(false, utils.Directory); err != nil {
return err
}
log.Infoln("creating database")
if err := Configs.CreateDatabase(); err != nil {
return err
}
log.Infoln("migrating database")
if err := Configs.MigrateDatabase(); err != nil {
return err
}
log.Infoln("insert large sample data into database")
if err := InsertLargeSampleData(); err != nil {
return err
}
log.Infoln("selecting the Core variable")
if CoreApp, err = SelectCore(); err != nil {
return err
}
log.Infoln("inserting notifiers into database")
if err := InsertNotifierDB(); err != nil {
return err
}
log.Infoln("loading all services")
if _, err := CoreApp.SelectAllServices(false); err != nil {
return err
}
log.Infoln("copying sql database file to: " + "/tmp/" + types.SqliteFilename)
if err := utils.CopyFile(sqlFile, "/tmp/"+types.SqliteFilename); err != nil {
return err
}
return err
}

View File

@ -2,10 +2,13 @@ package handlers
import ( import (
"fmt" "fmt"
"github.com/hunterlong/statping/core"
_ "github.com/hunterlong/statping/notifiers" _ "github.com/hunterlong/statping/notifiers"
"github.com/hunterlong/statping/source" "github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils" "github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -29,7 +32,9 @@ func init() {
} }
func TestResetDatabase(t *testing.T) { func TestResetDatabase(t *testing.T) {
Clean() err := core.TmpRecords("handlers.db")
require.Nil(t, err)
require.NotNil(t, core.CoreApp)
} }
func TestFailedHTTPServer(t *testing.T) { func TestFailedHTTPServer(t *testing.T) {
@ -59,7 +64,7 @@ func TestSetupRoutes(t *testing.T) {
Name: "Statping Setup Check", Name: "Statping Setup Check",
URL: "/setup", URL: "/setup",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 303,
}, },
{ {
Name: "Statping Run Setup", Name: "Statping Run Setup",
@ -68,7 +73,7 @@ func TestSetupRoutes(t *testing.T) {
Body: form.Encode(), Body: form.Encode(),
ExpectedStatus: 303, ExpectedStatus: 303,
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"}, HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
ExpectedFiles: []string{utils.Directory + "/config.yml", utils.Directory + "/statup.db"}, ExpectedFiles: []string{dir + "/config.yml", dir + "/" + types.SqliteFilename},
}} }}
for _, v := range tests { for _, v := range tests {
@ -89,7 +94,7 @@ func TestMainApiRoutes(t *testing.T) {
URL: "/api", URL: "/api",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{`"name":"Tester","description":"This is an awesome test"`}, ExpectedContains: []string{`"name":"Statping Sample Data","description":"This data is only used to testing"`},
}, },
{ {
Name: "Statping Renew API Keys", Name: "Statping Renew API Keys",
@ -113,11 +118,7 @@ func TestMainApiRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -234,11 +235,7 @@ func TestApiServiceRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -278,11 +275,7 @@ func TestGroupAPIRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -332,11 +325,7 @@ func TestApiUsersRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -369,11 +358,7 @@ func TestApiNotifiersRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -439,11 +424,7 @@ func TestMessagesApiRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -478,11 +459,7 @@ func TestApiCheckinRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }
@ -514,10 +491,7 @@ func RunHTTPTest(test HTTPTest, t *testing.T) (string, *testing.T, error) {
} }
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req) Router().ServeHTTP(rr, req)
if err != nil {
assert.Nil(t, err)
return "", t, err
}
body, err := ioutil.ReadAll(rr.Result().Body) body, err := ioutil.ReadAll(rr.Result().Body)
if err != nil { if err != nil {
assert.Nil(t, err) assert.Nil(t, err)
@ -540,9 +514,3 @@ func RunHTTPTest(test HTTPTest, t *testing.T) (string, *testing.T, error) {
} }
return stringBody, t, err return stringBody, t, err
} }
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/logs")
}

View File

@ -2,7 +2,7 @@ package handlers
import ( import (
"github.com/hunterlong/statping/utils" "github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"net/url" "net/url"
"testing" "testing"
) )
@ -27,7 +27,7 @@ func TestGenericRoutes(t *testing.T) {
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{ ExpectedContains: []string{
`<title>Tester Status</title>`, `<title>Statping Sample Data Status</title>`,
`<footer>`, `<footer>`,
}, },
}, },
@ -100,7 +100,7 @@ func TestGenericRoutes(t *testing.T) {
URL: "/metrics", URL: "/metrics",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{"statping_total_services 5"}, ExpectedContains: []string{"statping_total_services 15"},
}, },
{ {
Name: "Last Log Line", Name: "Last Log Line",
@ -140,10 +140,7 @@ func TestGenericRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }

View File

@ -1,7 +1,7 @@
package handlers package handlers
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"testing" "testing"
) )
@ -25,10 +25,7 @@ func TestMessageRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }

View File

@ -1,7 +1,7 @@
package handlers package handlers
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"testing" "testing"
) )
@ -31,10 +31,7 @@ func TestServiceRoutes(t *testing.T) {
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }

View File

@ -1,7 +1,7 @@
package handlers package handlers
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
"testing" "testing"
) )
@ -19,16 +19,13 @@ func TestUserRoutes(t *testing.T) {
URL: "/user/2", URL: "/user/2",
Method: "GET", Method: "GET",
ExpectedStatus: 200, ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping | adminuser2</title>`}, ExpectedContains: []string{`<title>Statping | testadmin2</title>`},
}} }}
for _, v := range tests { for _, v := range tests {
t.Run(v.Name, func(t *testing.T) { t.Run(v.Name, func(t *testing.T) {
_, t, err := RunHTTPTest(v, t) _, t, err := RunHTTPTest(v, t)
assert.Nil(t, err) require.Nil(t, err)
if err != nil {
t.FailNow()
}
}) })
} }
} }

View File

@ -15,14 +15,23 @@ gpgurl=https://statping.com/statping.gpg
repo=https://github.com/hunterlong/statping repo=https://github.com/hunterlong/statping
statping_get_tarball() { statping_get_tarball() {
url="$repo/releases/latest/download/statping-$1-$2.tar.gz" fext='tar.gz'
if [ ${OS} == 'windows' ]; then
fext='zip'
ARCH='x64'
fi
url="$repo/releases/latest/download/statping-$1-$2.$fext"
printf "$cyan> Downloading latest version for $OS $ARCH...\n$url $reset\n" printf "$cyan> Downloading latest version for $OS $ARCH...\n$url $reset\n"
# Get both the tarball and its GPG signature # Get both the tarball and its GPG signature
tarball_tmp=`mktemp -t statping.tar.gz.XXXXXXXXXX` tarball_tmp=`mktemp -t statping.tar.gz.XXXXXXXXXX`
if curl --fail -L -o "$tarball_tmp" "$url"; then if curl --fail -L -o "$tarball_tmp" "$url"; then
# All this dance is because `tar --strip=1` does not work everywhere # All this dance is because `tar --strip=1` does not work everywhere
temp=$(mktemp -d statping.XXXXXXXXXX) temp=$(mktemp -d statping.XXXXXXXXXX)
tar xzf $tarball_tmp -C "$temp" if [ ${OS} == 'windows' ]; then
unzip $tarball_tmp -d "$temp"
else
tar xzf $tarball_tmp -C "$temp"
fi
statping_verify_integrity "$temp"/statping statping_verify_integrity "$temp"/statping
printf "$green> Installing to $DEST/statping\n" printf "$green> Installing to $DEST/statping\n"
mv "$temp"/statping "$DEST" mv "$temp"/statping "$DEST"
@ -141,6 +150,14 @@ getOS() {
OS='windows' OS='windows'
DEST=/usr/local/bin DEST=/usr/local/bin
;; ;;
'MINGW*')
OS='windows'
DEST=/usr/local/bin
;;
'CYGWIN*')
OS='windows'
DEST=/usr/local/bin
;;
'Darwin') 'Darwin')
OS='osx' OS='osx'
DEST=/usr/local/bin DEST=/usr/local/bin

View File

@ -74,8 +74,8 @@ func init() {
} }
func injectDatabase() { func injectDatabase() {
utils.DeleteFile(dir + "/statup.db") utils.DeleteFile(dir + types.SqliteFilename)
db, err := gorm.Open("sqlite3", dir+"/statup.db") db, err := gorm.Open("sqlite3", dir+"notifiers.db")
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2019-12-28 08:54:51.387559 +0000 UTC // 2019-12-28 12:28:40.714078 +0000 UTC
// //
// This contains the most recently Markdown source for the Statping Wiki. // This contains the most recently Markdown source for the Statping Wiki.
package source package source

383
statuper
View File

@ -1,383 +0,0 @@
#!/usr/bin/env bash
VERSION="0.1"
VERBOSE=false
SSLOPTION=false
AWSREGION="us-west-2"
US_W_1="ami-6d1ffd0e"
US_W_2="ami-7be8a103"
US_E_1="ami-b3be85cc"
US_E_2="ami-cc7a40a9"
AMI_IMAGE=$US_W_2
AWS_CLI=$(which aws)
DOCKER_CLI=$(which docker)
DOCKER_IMG="hunterlong/statping"
AWS_ECS="$AWS_CLI --output json"
DOCKER_PORT=8080
function usage() {
cat <<EOM
##### Statping Installer #####
A simple shell script that will help you install Statping on your local machine, AWS, or Docker.
Commands:
install Install statping to your local system
aws Create a new EC2 instance running Statping
docker Start the latest Statping Docker image
docker-compose Create Statping with a Postgres database
version Return the latest version of Statping
Available Flags:
-k | --aws-access-key AWS Access Key ID. May also be set as environment variable AWS_ACCESS_KEY_ID
-s | --aws-secret-key AWS Secret Access Key. May also be set as environment variable AWS_SECRET_ACCESS_KEY
-r | --region AWS Region Name. May also be set as environment variable AWS_DEFAULT_REGION
-x | --verbose Verbose output
Visit the github repo at: https://github.com/hunterlong/statping
EOM
exit 3
}
# Check requirements
function require() {
getOS
command -v "$1" > /dev/null 2>&1 || {
echo "Some of the required software is not installed:"
APP="$1" >&2;
echo " Required application: $APP"
if [ $OS == "osx" ]; then
echo " You can run 'brew install $APP'"
elif [ $OS == "linux" ]; then
echo " You can run 'apt install $APP'"
fi
exit 4;
}
}
# Get the latest release from github
get_latest_release() {
STATPING_VERSION=$(curl --silent "https://api.github.com/repos/$DOCKER_IMG/releases/latest" | jq -r .tag_name)
}
# auto set AWS environment variables
function setAWSPresets {
if [ -z ${AWS_DEFAULT_REGION+x} ];
then unset AWS_DEFAULT_REGION
else
AWS_ECS="$AWS_ECS --region $AWS_DEFAULT_REGION"
fi
if [ -z ${AWS_PROFILE+x} ];
then unset AWS_PROFILE
else
AWS_ECS="$AWS_ECS --profile $AWS_PROFILE"
fi
}
# ask the user to inser their AWS region
function awsAskRegion {
if [ -z ${AWS_DEFAULT_REGION+x} ]; then
read -p "Enter the AWS Region: " AWSREGION
else
AWSREGION=$AWS_DEFAULT_REGION
fi
}
# ask for the EC2 instance name
function askEC2Name {
read -p "Enter the Name for EC2 Instance: " SERVERNAME
}
# ask user if they want to use SSL
function askSSLOption {
read -p "Do you want to install a SSL certificate? (y/N):" SSLOPTION
}
# ask user for domain for SSL
function askSSLDomain {
read -p "Enter the Domain to attach the SSL certificate on: " SSLDOMAIN
}
# ask user for email for Letencrypt
function askSSLEmail {
read -p "Enter the Email for Lets Encrypt: " SSLEMAIL
}
# ask user for their EC2 Keypair for instance
function askEC2KeyName {
read -p "Enter the Keypair for EC2 Instance: " EC2KEYNAME
}
# ask user to create a new AWS security group namne
function askSecurityName {
read -p "Enter a name for the new Security Group: " EC2SECGROUP
}
# ask user if they want to install statping to the bin folder
function askInstallGlobal {
read -p "Do you want to move Statping to the bin folder? (y/N): " MOVEBIN
}
# ask user if they want statping to start on boot
function askInstallSystemCTL {
read -p "Do you want to auto start Statping on boot? (y/N): " SYSTEMCTL
}
# Task to create a new AWS security group
function awsSecurityGroup {
echo "Running task: Creating Security Group";
GROUPID=`$AWS_ECS ec2 create-security-group --group-name "$EC2SECGROUP" --description "Statping HTTP Server on port 80 and 443" | jq -r .GroupId`
echo "Created new security group: $GROUPID";
awsAuthSecurityGroup
}
# Task to open ports 80 and 443 for the security group
function awsAuthSecurityGroup {
$AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 80 --cidr 0.0.0.0/0
$AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 443 --cidr 0.0.0.0/0
echo "Authorize security group to be open on ports 80 and 443";
}
function awsCreateEC2 {
NEW_SRV=`$AWS_ECS ec2 run-instances --image-id $US_W_2 --count 1 --instance-type t2.nano --key-name $EC2KEYNAME --security-group-ids $GROUPID`
INSTANCE_ID=$(echo "${NEW_SRV}" | jq -r .Instances[0].InstanceId)
EC2_STATUS=$(echo "${NEW_SRV}" | jq -r .Instances[0].StateReason.Message)
echo "New EC2 instance created: $INSTANCE_ID with status $EC2_STATUS";
}
# task to created a new EC2 instance with statping image
function ec2TaskComplete {
echo "New EC2 instance is ready! $INSTANCE_ID with status $EC2_STATUS";
echo "Instance ID: $INSTANCE_ID with status $EC2_STATUS";
echo "Public DNS: $EC2_DNS";
if [ $SSLOPTION == "y" ]; then
echo "Now you have to add a CNAME DNS record on $SSLDOMAIN pointing to $EC2_DNS"
fi
}
# function to check the EC2 instance
function checkEC2Instance {
SRV_INFO=`$AWS_ECS ec2 describe-instances --instance-ids $INSTANCE_ID`
EC2_STATUS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].State.Name)
EC2_DNS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].PublicDnsName)
EC2_STATUS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].State.Name)
if [ $EC2_STATUS == '"pending"' ]; then
echo "EC2 instance is still being created: $INSTANCE_ID";
sleep 2
checkEC2Instance
fi
}
# function to create the Statping EC2 instance
function awsTask {
setAWSPresets
askEC2Name
awsAskRegion
askSecurityName
askEC2KeyName
askSSLOption
if [ $SSLOPTION == "y" ]; then
askSSLDomain
askSSLEmail
fi
awsSecurityGroup
awsCreateEC2
checkEC2Instance
ec2TaskComplete
}
# function to move the statping binary to the bin folder
function moveToBin {
mv statping /usr/local/bin/statping
}
# function to install a systemctl service to the local system
function installSystemCTL {
FILE=statping.service
cat > $FILE <<- EOM
[Unit]
Description=Statping Server
After=network.target
After=systemd-user-sessions.service
After=network-online.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/statping
[Install]
WantedBy=multi-user.target
EOM
echo "Installing systemctl service file to: /etc/systemd/system/$FILE"
mv $FILE /etc/systemd/system/$FILE
systemctl daemon-reload
systemctl enable statping.service
systemctl start statping
echo "Statping has been installed to SystemCTL and will start on boot"
}
function downloadBin {
getOS
getArch
get_latest_release
GIT_DOWNLOAD="https://github.com/$DOCKER_IMG/releases/download/$STATPING_VERSION/statping-$OS-$ARCH.tar.gz"
echo "Downloading Statping $STATPING_VERSION from $GIT_DOWNLOAD"
curl -L --silent $GIT_DOWNLOAD | tar xz
echo "Download complete"
}
# install statping locally from github
function localTask {
downloadBin
echo "Try Statping by running 'statping version'!"
askInstallGlobal
if [ $MOVEBIN == "y" ]; then
moveToBin
echo "Statping can now be ran anywhere with command 'statping'"
echo "Install location: /usr/local/bin/statping"
if [ $OS == "linux" ]; then
askInstallSystemCTL
if [ $SYSTEMCTL == "y" ]; then
installSystemCTL
fi
fi
fi
}
function uninstallTask {
rm -f /usr/local/bin/statping
}
# start the Statping docker image
function dockerTask {
echo "Starting Statping Docker container on port $DOCKER_PORT"
$DOCKER_CLI run -d -p $DOCKER_PORT:8080 $DOCKER_IMG
}
# get 64x or 32 machine arch
function getArch {
MACHINE_TYPE=`uname -m`
if [ ${MACHINE_TYPE} == 'x86_64' ]; then
ARCH="x64"
else
ARCH="x32"
fi
}
# get the users operating system
function getOS {
OS="`uname`"
case $OS in
'Linux')
OS='linux'
alias ls='ls --color=auto'
;;
'FreeBSD')
OS='freebsd'
alias ls='ls -G'
;;
'WindowsNT')
OS='windows'
;;
'Darwin')
OS='osx'
;;
'SunOS')
OS='solaris'
;;
'AIX') ;;
*) ;;
esac
}
function echoVersion {
require jq
get_latest_release
echo "Statping Latest: $STATPING_VERSION"
echo "Statpinger Tool: v$VERSION"
}
# main CLI entrypoint
if [ "$BASH_SOURCE" == "$0" ]; then
set -o errexit
set -o pipefail
set -u
set -e
# If no args are provided, display usage information
if [ $# == 0 ]; then usage; fi
COMMD=$1
# Loop through arguments, two at a time for key and value
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-k|--aws-access-key)
AWS_ACCESS_KEY_ID="$2"
shift # past argument
;;
-s|--aws-secret-key)
AWS_SECRET_ACCESS_KEY="$2"
shift # past argument
;;
-r|--region)
AWS_DEFAULT_REGION="$2"
shift # past argument
;;
-p|--port)
DOCKER_PORT="$2"
shift # past argument
;;
-x|--verbose)
VERBOSE=true
;;
*)
;;
esac
shift # past argument or value
done
if [ $VERBOSE == true ]; then
set -x
fi
case $COMMD in
aws)
require aws
require jq
awsTask
exit 0
;;
docker)
require docker
dockerTask
exit 0
;;
docker-compose)
require docker-compose
dockerComposeTask
exit 0
;;
install)
require jq
require curl
require tar
localTask
shift # past argument
;;
uninstall)
uninstallTask
shift # past argument
;;
version|v)
echoVersion
exit 0
;;
*)
;;
esac
shift # past argument or value
fi
exit 0
fi

View File

@ -19,6 +19,9 @@ import (
"time" "time"
) )
// SqliteFilename is the name of the SQLlite database file
const SqliteFilename = "statping.db"
// AllNotifiers contains all the Notifiers loaded // AllNotifiers contains all the Notifiers loaded
type AllNotifiers interface{} type AllNotifiers interface{}

View File

@ -54,5 +54,6 @@ type DbConfig struct {
Email string `yaml:"-"` Email string `yaml:"-"`
Error error `yaml:"-"` Error error `yaml:"-"`
Location string `yaml:"location"` Location string `yaml:"location"`
SqlFile string `yaml:"sqlfile,omitempty"`
LocalIP string `yaml:"-"` LocalIP string `yaml:"-"`
} }

View File

@ -185,19 +185,46 @@ func FileExists(name string) bool {
// DeleteFile("newfile.json") // DeleteFile("newfile.json")
func DeleteFile(file string) error { func DeleteFile(file string) error {
Log.Infoln("deleting file: " + file) Log.Infoln("deleting file: " + file)
err := os.Remove(file) return os.Remove(file)
if err != nil {
return err
}
return nil
} }
// DeleteDirectory will attempt to delete a directory and all contents inside // DeleteDirectory will attempt to delete a directory and all contents inside
// DeleteDirectory("assets") // DeleteDirectory("assets")
func DeleteDirectory(directory string) error { func DeleteDirectory(directory string) error {
Log.Infoln("removing directory: " + directory)
return os.RemoveAll(directory) return os.RemoveAll(directory)
} }
// CreateDirectory will attempt to create a directory
// CreateDirectory("assets")
func CreateDirectory(directory string) error {
Log.Infoln("creating directory: " + directory)
return os.Mkdir(directory, os.ModePerm)
}
// CopyFile will copy a file to a new directory
// CopyFile("source.jpg", "/tmp/source.jpg")
func CopyFile(src, dst string) error {
Log.Infoln(fmt.Sprintf("copying file: %v to %v", src, dst))
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
// Command will run a terminal command with 'sh -c COMMAND' and return stdout and errOut as strings // Command will run a terminal command with 'sh -c COMMAND' and return stdout and errOut as strings
// in, out, err := Command("sass assets/scss assets/css/base.css") // in, out, err := Command("sass assets/scss assets/css/base.css")
func Command(cmd string) (string, string, error) { func Command(cmd string) (string, string, error) {