http table testing - source JS files

pull/130/head
hunterlong 2019-01-14 17:28:00 -08:00
parent 6e45bfdaea
commit 34c3964749
13 changed files with 971 additions and 955 deletions

510
handlers/api_test.go Normal file
View File

@ -0,0 +1,510 @@
package handlers
import (
"fmt"
_ "github.com/hunterlong/statping/notifiers"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)
const (
serverDomain = "http://localhost:8080"
)
var (
dir string
)
func init() {
source.Assets()
utils.InitLogs()
dir = utils.Directory
}
func TestResetDatabase(t *testing.T) {
Clean()
}
func TestFailedHTTPServer(t *testing.T) {
err := RunHTTPServer("missinghost", 0)
assert.Error(t, err)
}
func TestSetupRoutes(t *testing.T) {
form := url.Values{}
form.Add("db_host", "")
form.Add("db_user", "")
form.Add("db_password", "")
form.Add("db_database", "")
form.Add("db_connection", "sqlite")
form.Add("db_port", "")
form.Add("project", "Tester")
form.Add("username", "admin")
form.Add("password", "password123")
form.Add("sample_data", "on")
form.Add("description", "This is an awesome test")
form.Add("domain", "http://localhost:8080")
form.Add("email", "info@statping.com")
tests := []HTTPTest{
{
Name: "Statping Setup Check",
URL: "/setup",
Method: "GET",
ExpectedStatus: 200,
},
{
Name: "Statping Run Setup",
URL: "/setup",
Method: "POST",
Body: form.Encode(),
ExpectedStatus: 303,
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
ExpectedFiles: []string{utils.Directory + "/config.yml", utils.Directory + "/statup.db"},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestMainApiRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping Details",
URL: "/api",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`"name":"Tester","description":"This is an awesome test"`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestApiServiceRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping All Services",
URL: "/api/services",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`"id":1,"name":"Google","domain":"https://google.com"`},
},
{
Name: "Statping Service 1",
URL: "/api/services/1",
Method: "GET",
ExpectedContains: []string{`"id":1,"name":"Google","domain":"https://google.com"`},
ExpectedStatus: 200,
},
{
Name: "Statping Service 1 Data",
URL: "/api/services/1/data",
Method: "GET",
Body: "",
ExpectedStatus: 200,
},
{
Name: "Statping Service 1 Failures",
URL: "/api/services/1/failures",
Method: "GET",
Body: "",
ExpectedStatus: 200,
},
{
Name: "Statping Reorder Services",
URL: "/api/services/reorder",
Method: "POST",
Body: `[{"service":1,"order":1},{"service":5,"order":2},{"service":2,"order":3},{"service":3,"order":4},{"service":4,"order":5}]`,
ExpectedStatus: 200,
HttpHeaders: []string{"Content-Type=application/json"},
},
{
Name: "Statping Create Service",
URL: "/api/services",
HttpHeaders: []string{"Content-Type=application/json"},
Method: "POST",
Body: `{
"name": "New Service",
"domain": "https://statping.com",
"expected": "",
"expected_status": 200,
"check_interval": 30,
"type": "http",
"method": "GET",
"post_data": "",
"port": 0,
"timeout": 30,
"order_id": 0
}`,
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"service","method":"create"`},
},
{
Name: "Statping Update Service",
URL: "/api/services/1",
HttpHeaders: []string{"Content-Type=application/json"},
Method: "POST",
Body: `{
"name": "Updated New Service",
"domain": "https://google.com",
"expected": "",
"expected_status": 200,
"check_interval": 60,
"type": "http",
"method": "GET",
"post_data": "",
"port": 0,
"timeout": 10,
"order_id": 0
}`,
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"service","method":"update"`},
},
{
Name: "Statping Delete Service",
URL: "/api/services/1",
Method: "DELETE",
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"service","method":"delete"`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestGroupAPIRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping Groups",
URL: "/api/groups",
Method: "GET",
ExpectedStatus: 200,
},
{
Name: "Statping View Group",
URL: "/api/groups/1",
Method: "GET",
ExpectedStatus: 200,
},
{
Name: "Statping Create Group",
URL: "/api/groups",
HttpHeaders: []string{"Content-Type=application/json"},
Body: `{
"name": "New Group",
"public": true
}`,
Method: "POST",
ExpectedStatus: 200,
},
{
Name: "Statping Delete Group",
URL: "/api/groups/1",
Method: "DELETE",
ExpectedStatus: 200,
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestApiUsersRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping All Users",
URL: "/api/users",
Method: "GET",
ExpectedStatus: 200,
}, {
Name: "Statping Create User",
URL: "/api/users",
HttpHeaders: []string{"Content-Type=application/json"},
Method: "POST",
Body: `{
"username": "adminuser2",
"email": "info@adminemail.com",
"password": "passsword123",
"admin": true
}`,
ExpectedStatus: 200,
}, {
Name: "Statping View User",
URL: "/api/users/1",
Method: "GET",
ExpectedStatus: 200,
}, {
Name: "Statping Update User",
URL: "/api/users/1",
Method: "POST",
Body: `{
"username": "adminupdated",
"email": "info@email.com",
"password": "password12345",
"admin": true
}`,
ExpectedStatus: 200,
}, {
Name: "Statping Delete User",
URL: "/api/users/1",
Method: "DELETE",
ExpectedStatus: 200,
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestApiNotifiersRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping Notifiers",
URL: "/api/notifiers",
Method: "GET",
ExpectedStatus: 200,
}, {
Name: "Statping Mobile Notifier",
URL: "/api/notifier/mobile",
Method: "GET",
ExpectedStatus: 200,
}, {
Name: "Statping Update Notifier",
URL: "/api/notifier/mobile",
Method: "POST",
Body: `{
"method": "mobile",
"var1": "ExponentPushToken[ToBadIWillError123456]",
"enabled": true,
"limits": 55
}`,
ExpectedStatus: 200,
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestMessagesApiRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping Messages",
URL: "/api/messages",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`"id":1,"title":"Routine Downtime"`},
}, {
Name: "Statping Create Message",
URL: "/api/messages",
Method: "POST",
Body: `{
"title": "API Message",
"description": "This is an example a upcoming message for a service!",
"start_on": "2022-11-17T03:28:16.323797-08:00",
"end_on": "2022-11-17T05:13:16.323798-08:00",
"service": 1,
"notify_users": true,
"notify_method": "email",
"notify_before": 6,
"notify_before_scale": "hour"
}`,
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"message","method":"create"`},
},
{
Name: "Statping View Message",
URL: "/api/messages/1",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`"id":1,"title":"Routine Downtime"`},
}, {
Name: "Statping Update Message",
URL: "/api/messages/1",
Method: "POST",
Body: `{
"title": "Updated Message",
"description": "This message was updated",
"start_on": "2022-11-17T03:28:16.323797-08:00",
"end_on": "2022-11-17T05:13:16.323798-08:00",
"service": 1,
"notify_users": true,
"notify_method": "email",
"notify_before": 3,
"notify_before_scale": "hour"
}`,
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"message","method":"update"`},
},
{
Name: "Statping Delete Message",
URL: "/api/messages/1",
Method: "DELETE",
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"message","method":"delete"`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
func TestApiCheckinRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Statping Checkins",
URL: "/api/checkins",
Method: "GET",
ExpectedStatus: 200,
}, {
Name: "Statping Create Checkin",
URL: "/api/checkin",
Method: "POST",
Body: `{
"service_id": 2,
"name": "Server Checkin",
"interval": 900,
"grace": 60
}`,
ExpectedStatus: 200,
ExpectedContains: []string{`"status":"success","type":"checkin","method":"create"`},
},
{
Name: "Statping Checkins",
URL: "/api/checkins",
Method: "GET",
ExpectedStatus: 200,
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}
// HTTPTest contains all the parameters for a HTTP Unit Test
type HTTPTest struct {
Name string
URL string
Method string
Body string
ExpectedStatus int
ExpectedContains []string
HttpHeaders []string
ExpectedFiles []string
}
// RunHTTPTest accepts a HTTPTest type to execute the HTTP request
func RunHTTPTest(test HTTPTest, t *testing.T) (string, *testing.T, error) {
req, err := http.NewRequest(test.Method, serverDomain+test.URL, strings.NewReader(test.Body))
if err != nil {
assert.Nil(t, err)
return "", t, err
}
if len(test.HttpHeaders) != 0 {
for _, v := range test.HttpHeaders {
splits := strings.Split(v, "=")
req.Header.Set(splits[0], splits[1])
}
}
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
if err != nil {
assert.Nil(t, err)
return "", t, err
}
body, err := ioutil.ReadAll(rr.Result().Body)
if err != nil {
assert.Nil(t, err)
return "", t, err
}
stringBody := string(body)
if test.ExpectedStatus != rr.Result().StatusCode {
assert.Equal(t, test.ExpectedStatus, rr.Result().StatusCode)
return stringBody, t, fmt.Errorf("status code %v does not match %v", rr.Result().StatusCode, test.ExpectedStatus)
}
if len(test.ExpectedContains) != 0 {
for _, v := range test.ExpectedContains {
assert.Contains(t, stringBody, v)
}
}
if len(test.ExpectedFiles) != 0 {
for _, v := range test.ExpectedFiles {
assert.FileExists(t, v)
}
}
return stringBody, t, err
}
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/logs")
}

113
handlers/dashboard_test.go Normal file
View File

@ -0,0 +1,113 @@
package handlers
import (
"github.com/stretchr/testify/assert"
"net/url"
"testing"
)
func TestGenericRoutes(t *testing.T) {
form := url.Values{}
form.Add("username", "admin")
form.Add("password", "password123")
form2 := url.Values{}
form2.Add("username", "admin")
form2.Add("password", "wrongpassword")
tests := []HTTPTest{
{
Name: "Statping Index",
URL: "/",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{
`<title>Tester Status</title>`,
`<footer>`,
},
},
{
Name: "Statping Incorrect Login",
URL: "/dashboard",
Method: "POST",
Body: form.Encode(),
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
ExpectedContains: []string{"Incorrect login information submitted, try again."},
ExpectedStatus: 200,
},
{
Name: "Dashboard Routes",
URL: "/dashboard",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Dashboard</title>"},
},
{
Name: "Services Routes",
URL: "/services",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Services</title>"},
},
{
Name: "Users Routes",
URL: "/users",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Users</title>"},
},
{
Name: "Messages Routes",
URL: "/messages",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping Messages</title>"},
},
{
Name: "Settings Routes",
URL: "/settings",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Settings</title>"},
},
{
Name: "Logs Routes",
URL: "/logs",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Logs</title>"},
},
{
Name: "Help Routes",
URL: "/help",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"<title>Statping | Help</title>"},
},
{
Name: "Logout",
URL: "/logout",
Method: "GET",
ExpectedStatus: 303,
},
{
Name: "Prometheus Metrics Routes",
URL: "/metrics",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{"statping_total_services 5"},
},
}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}

View File

@ -1,493 +0,0 @@
// Statping
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
// https://github.com/hunterlong/statping
//
// The licenses for most software and other practical works are designed
// to take away your freedom to share and change the works. By contrast,
// the GNU General Public License is intended to guarantee your freedom to
// share and change all versions of a program--to make sure it remains free
// software for all its users.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers
import (
"github.com/hunterlong/statping/core"
_ "github.com/hunterlong/statping/notifiers"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
)
func TestResetHandlerDatabase(t *testing.T) {
Clean()
//loadDatabase()
//createDatabase()
}
func TestFailedHTTPServer(t *testing.T) {
err := RunHTTPServer("missinghost", 0)
assert.Error(t, err)
}
func TestSetupHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/setup", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Setup</title>")
}
func TestProcessSetupHandler(t *testing.T) {
form := url.Values{}
form.Add("db_host", "")
form.Add("db_user", "")
form.Add("db_password", "")
form.Add("db_database", "")
form.Add("db_connection", "sqlite")
form.Add("db_port", "")
form.Add("project", "Tester")
form.Add("username", "admin")
form.Add("password", "password123")
form.Add("sample_data", "on")
form.Add("description", "This is an awesome test")
form.Add("domain", "http://localhost:8080")
form.Add("email", "info@statping.com")
req, err := http.NewRequest("POST", "/setup", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.FileExists(t, dir+"/config.yml")
assert.FileExists(t, dir+"/statup.db")
}
func TestCheckSetupHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/setup", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
}
func TestCheckIndexHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 200, rr.Code)
}
func TestServicesViewHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/1", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Google Status</title>")
assert.Contains(t, body, "</footer>")
}
func TestMissingServiceViewHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/99999999", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 404, rr.Code)
}
func TestServiceChartHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/charts.js", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "var ctx_1")
assert.Contains(t, body, "var ctx_2")
assert.Contains(t, body, "var ctx_3")
assert.Contains(t, body, "var ctx_4")
assert.Contains(t, body, "var ctx_5")
}
func TestDashboardHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/dashboard", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Dashboard</title>")
assert.Contains(t, body, "</footer>")
}
func TestLoginHandler(t *testing.T) {
form := url.Values{}
form.Add("username", "admin")
form.Add("password", "password123")
req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
}
func TestBadLoginHandler(t *testing.T) {
form := url.Values{}
form.Add("username", "admin")
form.Add("password", "wrongpassword")
req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Contains(t, body, "Incorrect login information submitted, try again.")
assert.Equal(t, 200, rr.Code)
}
func TestServicesHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/services", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Services</title>")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestUsersHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/users", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Users</title>")
assert.Contains(t, body, "<td>admin</td>")
assert.NotContains(t, body, "<td>changedusername</td>")
assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestUsersEditHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/user/1", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | admin</title>")
assert.Contains(t, body, "<h3>User admin</h3>")
assert.Contains(t, body, "value=\"info@statping.com\"")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestSettingsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Settings</title>")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestHelpHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/help", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Help</title>")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestServicesHandler2(t *testing.T) {
req, err := http.NewRequest("GET", "/services", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Services</title>")
assert.Contains(t, body, "JSON Users Test")
assert.Contains(t, body, "JSON API Tester")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestViewHTTPServicesHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/5", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Google DNS Status</title>")
//assert.Contains(t, body, "</footer>")
}
func TestViewTCPServicesHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/5", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Google DNS Status</title>")
//assert.Contains(t, body, "</footer>")
}
func TestServicesDeleteFailuresHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/5/delete_failures", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
}
func TestFailingServicesDeleteFailuresHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/service/5/delete_failures", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
}
func TestLogsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/logs", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Logs</title>")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestLogsLineHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/logs/line", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.NotEmpty(t, body)
assert.True(t, isRouteAuthenticated(req))
}
func TestSaveSettingsHandler(t *testing.T) {
form := url.Values{}
form.Add("project", "Awesome Status")
form.Add("description", "These tests can probably be better")
req, err := http.NewRequest("POST", "/settings", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
}
func TestViewSettingsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Settings</title>")
assert.Contains(t, body, "Awesome Status")
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestSaveAssetsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings/build", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.FileExists(t, utils.Directory+"/assets/css/base.css")
assert.DirExists(t, utils.Directory+"/assets")
assert.True(t, source.UsingAssets(dir))
assert.True(t, isRouteAuthenticated(req))
}
func TestDeleteAssetsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings/delete_assets", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.False(t, source.UsingAssets(dir))
assert.True(t, isRouteAuthenticated(req))
}
func TestPrometheusHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/metrics", nil)
req.Header.Set("Authorization", core.CoreApp.ApiSecret)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "statping_total_services 5")
assert.True(t, isRouteAuthenticated(req))
}
func TestUpdateNotificationHandler(t *testing.T) {
t.SkipNow()
data := `{"limits": 7, "enabled": true, "method": "email", "host": "smtp.emailserver.com", "username": "exampleuser", "password": "password123", "port": 543, "var1": "info@betatude.com", "var2": "sendto@gmail.com"}`
rr, err := httpRequestAPI(t, "POST", "/api/notifier/email", strings.NewReader(data))
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "success", obj.Status)
}
func TestViewNotificationSettingsHandler(t *testing.T) {
t.SkipNow()
req, err := http.NewRequest("GET", "/settings", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "<title>Statping | Settings</title>")
assert.Contains(t, body, `value="exampleuser" id="smtp_username"`)
assert.Contains(t, body, `value="587" id="smtp_port"`)
assert.Contains(t, body, `value="info@betatude.com" id="outgoing_email_address"`)
assert.Contains(t, body, `value="sendto@gmail.com" id="send_alerts_to"`)
assert.Contains(t, body, `id="limits_per_hour_email" value="7"`)
assert.Contains(t, body, `id="switch-email" checked`)
//assert.Contains(t, body, "</footer>")
assert.True(t, isRouteAuthenticated(req))
}
func TestSaveFooterHandler(t *testing.T) {
form := url.Values{}
form.Add("footer", "Created by Hunter Long")
req, err := http.NewRequest("POST", "/settings", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
req, err = http.NewRequest("GET", "/", nil)
assert.Nil(t, err)
rr = httptest.NewRecorder()
Router().ServeHTTP(rr, req)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
assert.Contains(t, body, "Created by Hunter Long")
}
func TestError404Handler(t *testing.T) {
req, err := http.NewRequest("GET", "/404me", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 404, rr.Code)
}
func TestLogoutHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/logout", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
}
func TestBuildAssetsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings/build", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
assert.FileExists(t, "../assets/scss/base.scss")
}
func TestSaveSassHandler(t *testing.T) {
base := source.OpenAsset(utils.Directory, "scss/base.scss")
vars := source.OpenAsset(utils.Directory, "scss/variables.scss")
form := url.Values{}
form.Add("theme", base+"\n .test_design { color: $test-design; }")
form.Add("variables", vars+"\n $test-design: #ffffff; ")
req, err := http.NewRequest("POST", "/settings/css", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code)
assert.True(t, isRouteAuthenticated(req))
newBase := source.OpenAsset(utils.Directory, "css/base.css")
assert.Contains(t, newBase, ".test_design {")
}
func TestReorderServiceHandler(t *testing.T) {
data := `[{id: 1, order: 3},{id: 2, order: 2},{id: 3, order: 1}]"`
req, err := http.NewRequest("POST", "/api/services/reorder", strings.NewReader(data))
req.Header.Set("Content-Type", "application/json")
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 200, rr.Code)
assert.True(t, isRouteAuthenticated(req))
}
func TestExportHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/settings/export", nil)
assert.Nil(t, err)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Equal(t, 200, rr.Code)
assert.True(t, isRouteAuthenticated(req))
}
func isRouteAuthenticated(req *http.Request) bool {
os.Setenv("GO_ENV", "production")
rr := httptest.NewRecorder()
req.Header.Set("Authorization", "badkey")
Router().ServeHTTP(rr, req)
code := rr.Code
if code == 200 {
os.Setenv("GO_ENV", "test")
return false
}
os.Setenv("GO_ENV", "test")
return true
}

35
handlers/messages_test.go Normal file
View File

@ -0,0 +1,35 @@
package handlers
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestMessageRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Messages",
URL: "/messages",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping Messages</title>`},
},
{
Name: "Message 2",
URL: "/message/2",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping | Server Reboot</title>`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}

View File

@ -1,327 +0,0 @@
// Statping
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
// https://github.com/hunterlong/statping
//
// The licenses for most software and other practical works are designed
// to take away your freedom to share and change the works. By contrast,
// the GNU General Public License is intended to guarantee your freedom to
// share and change all versions of a program--to make sure it remains free
// software for all its users.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package handlers
import (
"encoding/json"
"github.com/hunterlong/statping/core"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"github.com/stretchr/testify/assert"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
const (
NEW_HTTP_SERVICE = `{"name": "Google Website", "domain": "https://google.com", "expected_status": 200, "check_interval": 10, "type": "http", "method": "GET"}`
)
var (
dir string
)
func init() {
dir = utils.Directory
utils.InitLogs()
source.Assets()
}
func loadDatabase() {
core.NewCore()
core.LoadConfigFile(dir)
core.Configs = &core.DbConfig{
DbConn: "sqlite",
Location: dir,
}
core.CoreApp.DbConnection = "sqlite"
core.Configs.Connect(false, utils.Directory)
core.CoreApp.Version = "DEV"
core.Configs.Save()
}
func createDatabase() {
core.Configs.DropDatabase()
core.Configs.CreateDatabase()
}
func resetDatabase() {
core.Configs.DropDatabase()
core.Configs.CreateDatabase()
core.InsertLargeSampleData()
}
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/assets")
utils.DeleteDirectory(dir + "/logs")
}
func TestInit(t *testing.T) {
//Clean()
//loadDatabase()
//resetDatabase()
//loadDatabase()
//core.SelectCore()
//core.InsertNotifierDB()
//core.CoreApp.SelectAllServices(false)
//core.CoreApp.Notifications = notifier.Load()
}
func formatJSON(res string, out interface{}) {
json.Unmarshal([]byte(res), &out)
}
func TestApiIndexHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj types.Core
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "Awesome Status", obj.Name)
assert.Equal(t, "sqlite", obj.DbConnection)
}
func TestApiAllServicesHandlerHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api/services", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj []types.Service
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "Google", obj[0].Name)
assert.Equal(t, "https://google.com", obj[0].Domain)
}
func TestApiServiceHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api/services/1", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj types.Service
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "Google", obj.Name)
assert.Equal(t, "https://google.com", obj.Domain)
}
func TestApiCreateServiceHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "POST", "/api/services", strings.NewReader(NEW_HTTP_SERVICE))
assert.Nil(t, err)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
var obj apiResponse
formatJSON(body, &obj)
t.Log(body)
object := obj.Output.(map[string]interface{})
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "Google Website", object["name"])
assert.Equal(t, "https://google.com", object["domain"])
}
func TestApiUpdateServiceHandler(t *testing.T) {
data := `{
"name": "Updated Service",
"domain": "https://google.com",
"expected": "",
"expected_status": 200,
"check_interval": 60,
"type": "http",
"method": "GET",
"post_data": "",
"port": 0,
"timeout": 10,
"order_id": 0}`
rr, err := httpRequestAPI(t, "POST", "/api/services/1", strings.NewReader(data))
assert.Nil(t, err)
body := rr.Body.String()
t.Log(body)
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "success", obj.Status)
assert.Equal(t, "update", obj.Method)
assert.Equal(t, int64(1), obj.Id)
}
func TestApiDeleteServiceHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "DELETE", "/api/services/2", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "delete", obj.Method)
assert.Equal(t, "success", obj.Status)
}
func TestApiAllUsersHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api/users", nil)
assert.Nil(t, err)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
var obj []types.User
formatJSON(body, &obj)
assert.Equal(t, true, obj[0].Admin.Bool)
assert.Equal(t, "admin", obj[0].Username)
}
func TestApiCreateUserHandler(t *testing.T) {
data := `{
"username": "admin2",
"email": "info@email.com",
"password": "password123",
"admin": true}`
rr, err := httpRequestAPI(t, "POST", "/api/users", strings.NewReader(data))
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
t.Log(body)
assert.Equal(t, 200, rr.Code)
assert.Contains(t, "create", obj.Method)
assert.Contains(t, "success", obj.Status)
}
func TestApiViewUserHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api/users/1", nil)
assert.Nil(t, err)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
var obj types.User
formatJSON(body, &obj)
t.Log(body)
assert.Equal(t, "admin", obj.Username)
assert.Equal(t, true, obj.Admin.Bool)
}
func TestApiUpdateUserHandler(t *testing.T) {
data := `{
"username": "adminupdated",
"password": "password123",
"admin": true}`
rr, err := httpRequestAPI(t, "POST", "/api/users/1", strings.NewReader(data))
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
t.Log(body)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "update", obj.Method)
assert.Equal(t, "success", obj.Status)
assert.Equal(t, int64(1), obj.Id)
}
func TestApiDeleteUserHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "DELETE", "/api/users/1", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "delete", obj.Method)
assert.Equal(t, "success", obj.Status)
}
func TestApiServiceDataHandler(t *testing.T) {
grouping := []string{"minute", "hour", "day", "week"}
for _, g := range grouping {
params := "?start=0&end=999999999999&group=" + g
rr, err := httpRequestAPI(t, "GET", "/api/services/5/data"+params, nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj core.DateScanObj
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
assert.NotZero(t, len(obj.Array))
}
}
func TestApiRenewHandler(t *testing.T) {
api := core.CoreApp.ApiKey
secret := core.CoreApp.ApiSecret
rr, err := httpRequestAPI(t, "GET", "/api/renew", nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 303, rr.Code)
assert.NotEqual(t, api, core.CoreApp.ApiKey)
assert.NotEqual(t, secret, core.CoreApp.ApiSecret)
}
func TestApiCheckinHandler(t *testing.T) {
t.SkipNow()
service := core.SelectService(1)
checkin := service.AllCheckins()
rr, err := httpRequestAPI(t, "GET", "/api/checkin/"+checkin[0].ApiKey, nil)
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
assert.Equal(t, 200, rr.Code)
}
func TestApiCreateCheckinHandler(t *testing.T) {
data := `{
"service_id": 1,
"name": "New API Checkin",
"interval": 60,
"grace": 30}`
rr, err := httpRequestAPI(t, "POST", "/api/checkin", strings.NewReader(data))
assert.Nil(t, err)
body := rr.Body.String()
var obj apiResponse
formatJSON(body, &obj)
t.Log(body)
assert.Equal(t, 200, rr.Code)
assert.Equal(t, "create", obj.Method)
assert.Equal(t, "success", obj.Status)
assert.Equal(t, int64(1), obj.Id)
}
func TestApiAllCheckinsHandler(t *testing.T) {
rr, err := httpRequestAPI(t, "GET", "/api/checkins", nil)
assert.Nil(t, err)
body := rr.Body.String()
assert.Equal(t, 200, rr.Code)
var obj []types.Checkin
formatJSON(body, &obj)
t.Log(body)
assert.Equal(t, int(1), len(obj))
assert.Equal(t, int64(1), obj[0].Id)
assert.Equal(t, int64(1), obj[0].ServiceId)
assert.Equal(t, "New API Checkin", obj[0].Name)
}
func httpRequestAPI(t *testing.T, method, url string, body io.Reader) (*httptest.ResponseRecorder, error) {
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Authorization", core.CoreApp.ApiSecret)
rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req)
assert.Nil(t, err)
return rr, err
}

View File

@ -40,17 +40,18 @@ func Router() *mux.Router {
indexHandler := http.FileServer(http.Dir(dir + "/assets/"))
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir(dir+"/assets/css"))))
r.PathPrefix("/font/").Handler(http.StripPrefix("/font/", http.FileServer(http.Dir(dir+"/assets/font"))))
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", http.FileServer(http.Dir(dir+"/assets/js"))))
r.PathPrefix("/robots.txt").Handler(indexHandler)
r.PathPrefix("/favicon.ico").Handler(indexHandler)
r.PathPrefix("/banner.png").Handler(indexHandler)
} else {
r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(source.CssBox.HTTPBox())))
r.PathPrefix("/font/").Handler(http.StripPrefix("/font/", http.FileServer(source.FontBox.HTTPBox())))
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", http.FileServer(source.JsBox.HTTPBox())))
r.PathPrefix("/robots.txt").Handler(http.FileServer(source.TmplBox.HTTPBox()))
r.PathPrefix("/favicon.ico").Handler(http.FileServer(source.TmplBox.HTTPBox()))
r.PathPrefix("/banner.png").Handler(http.FileServer(source.TmplBox.HTTPBox()))
}
r.PathPrefix("/js/").Handler(http.StripPrefix("/js/", http.FileServer(source.JsBox.HTTPBox())))
r.Handle("/charts.js", http.HandlerFunc(renderServiceChartsHandler))
r.Handle("/setup", http.HandlerFunc(setupHandler)).Methods("GET")
r.Handle("/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")

35
handlers/services_test.go Normal file
View File

@ -0,0 +1,35 @@
package handlers
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestServiceRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Services",
URL: "/services",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping | Services</title>`},
},
{
Name: "Services 2",
URL: "/service/2",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping Github Status</title>`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}

35
handlers/users_test.go Normal file
View File

@ -0,0 +1,35 @@
package handlers
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestUserRoutes(t *testing.T) {
tests := []HTTPTest{
{
Name: "Users",
URL: "/users",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping | Users</title>`},
},
{
Name: "User 2",
URL: "/user/2",
Method: "GET",
ExpectedStatus: 200,
ExpectedContains: []string{`<title>Statping | adminuser2</title>`},
}}
for _, v := range tests {
t.Run(v.Name, func(t *testing.T) {
body, t, err := RunHTTPTest(v, t)
assert.Nil(t, err)
if err != nil {
t.FailNow()
}
t.Logf("Test %v got: %v\n", v.Name, string(body))
})
}
}

View File

@ -7,54 +7,66 @@
/* Mobile Service Container */
HTML, BODY {
background-color: #fcfcfc;
padding-bottom: 10px; }
padding-bottom: 10px;
}
.container {
padding-top: 20px;
padding-bottom: 25px;
max-width: 860px;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; }
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
}
.header-title {
color: #464646; }
color: #464646;
}
.header-desc {
color: #939393; }
color: #939393;
}
.btn {
border-radius: 0.2rem; }
border-radius: 0.2rem;
}
.online_list .badge {
margin-top: 0.2rem; }
margin-top: 0.2rem;
}
.navbar {
margin-bottom: 30px; }
margin-bottom: 30px;
}
.btn-sm {
line-height: 1.3;
font-size: 0.75rem; }
font-size: 0.75rem;
}
.view_service_btn {
position: absolute;
bottom: -40px;
right: 40px; }
right: 40px;
}
.service_lower_info {
position: absolute;
bottom: -40px;
left: 40px;
color: #d1ffca;
font-size: 0.85rem; }
font-size: 0.85rem;
}
.lg_number {
font-size: 2.3rem;
font-weight: bold;
display: block;
color: #4f4f4f; }
color: #4f4f4f;
}
.stats_area {
text-align: center;
color: #a5a5a5; }
color: #a5a5a5;
}
.lower_canvas {
height: 3.4rem;
@ -62,112 +74,144 @@ HTML, BODY {
background-color: #48d338;
padding: 15px 10px;
margin-left: 0px !important;
margin-right: 0px !important; }
margin-right: 0px !important;
}
.lower_canvas SPAN {
font-size: 1rem;
color: #fff; }
color: #fff;
}
.footer {
text-decoration: none;
margin-top: 20px; }
margin-top: 20px;
}
.footer A {
color: #8d8d8d;
text-decoration: none; }
text-decoration: none;
}
.footer A:HOVER {
color: #6d6d6d; }
color: #6d6d6d;
}
.badge {
color: white;
border-radius: 0.2rem; }
border-radius: 0.2rem;
}
.btn-group {
height: 25px; }
.btn-group A {
padding: 0.1rem .75rem;
font-size: 0.8rem; }
height: 25px;
}
.btn-group A {
padding: 0.1rem 0.75rem;
font-size: 0.8rem;
}
.card-body .badge {
color: #fff; }
color: #fff;
}
.nav-pills .nav-link {
border-radius: 0.2rem; }
border-radius: 0.2rem;
}
.form-control {
border-radius: 0.2rem; }
border-radius: 0.2rem;
}
.card {
background-color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.125); }
border: 1px solid rgba(0, 0, 0, 0.125);
}
.card-body {
overflow: hidden; }
overflow: hidden;
}
.card-body H4 A {
color: #444444;
text-decoration: none; }
text-decoration: none;
}
.chart-container {
position: relative;
height: 170px;
width: 100%; }
width: 100%;
}
.service-chart-container {
position: relative;
height: 400px;
width: 100%; }
width: 100%;
}
.btn-primary {
background-color: #3e9bff;
border-color: #006fe6;
color: white; }
.btn-primary.dyn-dark {
background-color: #32a825 !important;
border-color: #2c9320 !important; }
.btn-primary.dyn-light {
background-color: #75de69 !important;
border-color: #88e37e !important; }
color: white;
}
.btn-primary.dyn-dark {
background-color: #32a825 !important;
border-color: #2c9320 !important;
}
.btn-primary.dyn-light {
background-color: #75de69 !important;
border-color: #88e37e !important;
}
.btn-success {
background-color: #47d337; }
.btn-success.dyn-dark {
background-color: #32a825 !important;
border-color: #2c9320 !important; }
.btn-success.dyn-light {
background-color: #75de69 !important;
border-color: #88e37e !important; }
background-color: #47d337;
}
.btn-success.dyn-dark {
background-color: #32a825 !important;
border-color: #2c9320 !important;
}
.btn-success.dyn-light {
background-color: #75de69 !important;
border-color: #88e37e !important;
}
.btn-danger {
background-color: #dd3545; }
.btn-danger.dyn-dark {
background-color: #b61f2d !important;
border-color: #a01b28 !important; }
.btn-danger.dyn-light {
background-color: #e66975 !important;
border-color: #e97f89 !important; }
background-color: #dd3545;
}
.btn-danger.dyn-dark {
background-color: #b61f2d !important;
border-color: #a01b28 !important;
}
.btn-danger.dyn-light {
background-color: #e66975 !important;
border-color: #e97f89 !important;
}
.bg-success {
background-color: #47d337 !important; }
background-color: #47d337 !important;
}
.bg-danger {
background-color: #dd3545 !important; }
background-color: #dd3545 !important;
}
.bg-success .dyn-dark {
background-color: #35b027 !important; }
background-color: #35b027 !important;
}
.bg-danger .dyn-dark {
background-color: #bf202f !important; }
background-color: #bf202f !important;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
background-color: #13a00d; }
background-color: #13a00d;
}
.nav-pills A {
color: #424242; }
color: #424242;
}
.nav-pills I {
margin-right: 10px; }
margin-right: 10px;
}
.CodeMirror {
/* Bootstrap Settings */
@ -187,23 +231,26 @@ HTML, BODY {
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
/* Code Mirror Settings */
font-family: monospace;
position: relative;
overflow: hidden;
height: 80vh; }
height: 80vh;
}
.CodeMirror-focused {
/* Bootstrap Settings */
border-color: #66afe9;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; }
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.switch {
font-size: 1rem;
position: relative; }
position: relative;
}
.switch input {
position: absolute;
@ -214,7 +261,8 @@ HTML, BODY {
clip: rect(0 0 0 0);
clip-path: inset(50%);
overflow: hidden;
padding: 0; }
padding: 0;
}
.switch input + label {
position: relative;
@ -227,23 +275,26 @@ HTML, BODY {
outline: none;
user-select: none;
vertical-align: middle;
text-indent: calc(calc(calc(2.375rem * .8) * 2) + .5rem); }
text-indent: calc(calc(calc(2.375rem * .8) * 2) + .5rem);
}
.switch input + label::before,
.switch input + label::after {
content: '';
content: "";
position: absolute;
top: 0;
left: 0;
width: calc(calc(2.375rem * .8) * 2);
bottom: 0;
display: block; }
display: block;
}
.switch input + label::before {
right: 0;
background-color: #dee2e6;
border-radius: calc(2.375rem * .8);
transition: 0.2s all; }
transition: 0.2s all;
}
.switch input + label::after {
top: 2px;
@ -252,120 +303,154 @@ HTML, BODY {
height: calc(calc(2.375rem * .8) - calc(2px * 2));
border-radius: 50%;
background-color: white;
transition: 0.2s all; }
transition: 0.2s all;
}
.switch input:checked + label::before {
background-color: #08d; }
background-color: #08d;
}
.switch input:checked + label::after {
margin-left: calc(2.375rem * .8); }
margin-left: calc(2.375rem * .8);
}
.switch input:focus + label::before {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 136, 221, 0.25); }
box-shadow: 0 0 0 0.2rem rgba(0, 136, 221, 0.25);
}
.switch input:disabled + label {
color: #868e96;
cursor: not-allowed; }
cursor: not-allowed;
}
.switch input:disabled + label::before {
background-color: #e9ecef; }
background-color: #e9ecef;
}
.switch.switch-sm {
font-size: 0.875rem; }
font-size: 0.875rem;
}
.switch.switch-sm input + label {
min-width: calc(calc(1.9375rem * .8) * 2);
height: calc(1.9375rem * .8);
line-height: calc(1.9375rem * .8);
text-indent: calc(calc(calc(1.9375rem * .8) * 2) + .5rem); }
text-indent: calc(calc(calc(1.9375rem * .8) * 2) + .5rem);
}
.switch.switch-sm input + label::before {
width: calc(calc(1.9375rem * .8) * 2); }
width: calc(calc(1.9375rem * .8) * 2);
}
.switch.switch-sm input + label::after {
width: calc(calc(1.9375rem * .8) - calc(2px * 2));
height: calc(calc(1.9375rem * .8) - calc(2px * 2)); }
height: calc(calc(1.9375rem * .8) - calc(2px * 2));
}
.switch.switch-sm input:checked + label::after {
margin-left: calc(1.9375rem * .8); }
margin-left: calc(1.9375rem * .8);
}
.switch.switch-lg {
font-size: 1.25rem; }
font-size: 1.25rem;
}
.switch.switch-lg input + label {
min-width: calc(calc(3rem * .8) * 2);
height: calc(3rem * .8);
line-height: calc(3rem * .8);
text-indent: calc(calc(calc(3rem * .8) * 2) + .5rem); }
text-indent: calc(calc(calc(3rem * .8) * 2) + .5rem);
}
.switch.switch-lg input + label::before {
width: calc(calc(3rem * .8) * 2); }
width: calc(calc(3rem * .8) * 2);
}
.switch.switch-lg input + label::after {
width: calc(calc(3rem * .8) - calc(2px * 2));
height: calc(calc(3rem * .8) - calc(2px * 2)); }
height: calc(calc(3rem * .8) - calc(2px * 2));
}
.switch.switch-lg input:checked + label::after {
margin-left: calc(3rem * .8); }
margin-left: calc(3rem * .8);
}
.switch + .switch {
margin-left: 1rem; }
margin-left: 1rem;
}
@keyframes pulse_animation {
0% {
transform: scale(1); }
transform: scale(1);
}
30% {
transform: scale(1); }
transform: scale(1);
}
40% {
transform: scale(1.02); }
transform: scale(1.02);
}
50% {
transform: scale(1); }
transform: scale(1);
}
60% {
transform: scale(1); }
transform: scale(1);
}
70% {
transform: scale(1.05); }
transform: scale(1.05);
}
80% {
transform: scale(1); }
transform: scale(1);
}
100% {
transform: scale(1); } }
transform: scale(1);
}
}
.pulse {
animation-name: pulse_animation;
animation-duration: 1500ms;
transform-origin: 70% 70%;
animation-iteration-count: infinite;
animation-timing-function: linear; }
animation-timing-function: linear;
}
@keyframes glow-grow {
0% {
opacity: 0;
transform: scale(1); }
transform: scale(1);
}
80% {
opacity: 1; }
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0; } }
opacity: 0;
}
}
.pulse-glow {
animation-name: glow-grown;
animation-duration: 100ms;
transform-origin: 70% 30%;
animation-iteration-count: infinite;
animation-timing-function: linear; }
animation-timing-function: linear;
}
.pulse-glow:before,
.pulse-glow:after {
position: absolute;
content: '';
content: "";
height: 0.5rem;
width: 1.75rem;
top: 1.2rem;
right: 2.15rem;
border-radius: 0;
box-shadow: 0 0 7px #47d337;
animation: glow-grow 2s ease-out infinite; }
animation: glow-grow 2s ease-out infinite;
}
.sortable_drag {
background-color: #0000000f; }
background-color: #0000000f;
}
.drag_icon {
cursor: move;
@ -379,106 +464,132 @@ HTML, BODY {
margin-right: 5px;
margin-left: -10px;
text-align: center;
color: #b1b1b1; }
color: #b1b1b1;
}
/* (Optional) Apply a "closed-hand" cursor during drag operation. */
.drag_icon:active {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing; }
cursor: -webkit-grabbing;
}
.switch_btn {
float: right;
margin: -1px 0px 0px 0px;
display: block; }
display: block;
}
#start_container {
position: absolute;
z-index: 99999;
margin-top: 20px; }
margin-top: 20px;
}
#end_container {
position: absolute;
z-index: 99999;
margin-top: 20px;
right: 0; }
right: 0;
}
.pointer {
cursor: pointer; }
cursor: pointer;
}
.jumbotron {
background-color: white; }
background-color: white;
}
@media (max-width: 767px) {
HTML, BODY {
background-color: #fcfcfc; }
background-color: #fcfcfc;
}
.sm-container {
margin-top: 0px !important;
padding: 0 !important; }
padding: 0 !important;
}
.list-group-item H5 {
font-size: 0.9rem; }
font-size: 0.9rem;
}
.container {
padding: 0px !important;
padding-top: 15px !important; }
padding-top: 15px !important;
}
.group_header {
margin-left: 15px; }
margin-left: 15px;
}
.navbar {
margin-left: 0px;
margin-top: 0px;
width: 100%;
margin-bottom: 0; }
margin-bottom: 0;
}
.btn-sm {
line-height: 0.9rem;
font-size: 0.65rem; }
font-size: 0.65rem;
}
.full-col-12 {
padding-left: 0px;
padding-right: 0px; }
padding-right: 0px;
}
.card {
border: 0;
border-radius: 0rem;
padding: 0;
background-color: #ffffff; }
background-color: #ffffff;
}
.card-body {
font-size: 10pt;
padding: 0px 10px; }
padding: 0px 10px;
}
.lg_number {
font-size: 7.8vw; }
font-size: 7.8vw;
}
.stats_area {
margin-top: 1.5rem !important;
margin-bottom: 1.5rem !important; }
margin-bottom: 1.5rem !important;
}
.stats_area .col-4 {
padding-left: 0;
padding-right: 0;
font-size: 0.6rem; }
font-size: 0.6rem;
}
.list-group-item {
border-top: 1px solid #e4e4e4;
border: 0px; }
border: 0px;
}
.list-group-item:first-child {
border-top-left-radius: 0;
border-top-right-radius: 0; }
border-top-right-radius: 0;
}
.list-group-item:last-child {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0; }
border-bottom-left-radius: 0;
}
.list-group-item P {
font-size: 0.7rem; }
font-size: 0.7rem;
}
.service-chart-container {
height: 200px; } }
height: 200px;
}
}
/*# sourceMappingURL=base.css.map */

View File

@ -40,8 +40,8 @@ func TestCore_UsingAssets(t *testing.T) {
func TestCreateAssets(t *testing.T) {
assert.Nil(t, CreateAllAssets(dir))
assert.True(t, UsingAssets(dir))
assert.FileExists(t, "../assets/css/base.css")
assert.FileExists(t, "../assets/scss/base.scss")
assert.FileExists(t, "./assets/css/base.css")
assert.FileExists(t, "./assets/scss/base.scss")
}
func TestCompileSASS(t *testing.T) {

View File

@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2019-01-10 12:48:42.676069 -0800 PST m=+0.785435129
// 2019-01-14 17:21:53.045328 -0800 PST m=+0.787121391
//
// This contains the most recently Markdown source for the Statping Wiki.
package source

View File

@ -31,11 +31,7 @@ func TestCreateLog(t *testing.T) {
func TestInitLogs(t *testing.T) {
assert.Nil(t, InitLogs())
assert.FileExists(t, "../logs/statup.log")
}
func TestFileExists(t *testing.T) {
assert.True(t, FileExists("../logs/statup.log"))
assert.FileExists(t, "./logs/statup.log")
}
func TestDir(t *testing.T) {

View File

@ -1 +1 @@
0.80.36
0.80.37