Add health api
This commit is contained in:
parent
ad157a138b
commit
81c4a73df3
|
|
@ -0,0 +1,46 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gotify/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The HealthDatabase interface for encapsulating database access.
|
||||||
|
type HealthDatabase interface {
|
||||||
|
Ping() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// The HealthAPI provides handlers for the health information.
|
||||||
|
type HealthAPI struct {
|
||||||
|
DB HealthDatabase
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health returns health information.
|
||||||
|
// swagger:operation GET /health health getHealth
|
||||||
|
//
|
||||||
|
// Get health information.
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// produces: [application/json]
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Health"
|
||||||
|
// 500:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Health"
|
||||||
|
func (a *HealthAPI) Health(ctx *gin.Context) {
|
||||||
|
if err := a.DB.Ping(); err != nil {
|
||||||
|
ctx.JSON(500, model.Health{
|
||||||
|
Health: model.StatusOrange,
|
||||||
|
Database: model.StatusRed,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(200, model.Health{
|
||||||
|
Health: model.StatusGreen,
|
||||||
|
Database: model.StatusGreen,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gotify/server/mode"
|
||||||
|
"github.com/gotify/server/model"
|
||||||
|
"github.com/gotify/server/test"
|
||||||
|
"github.com/gotify/server/test/testdb"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHealthSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(HealthSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
db *testdb.Database
|
||||||
|
a *HealthAPI
|
||||||
|
ctx *gin.Context
|
||||||
|
recorder *httptest.ResponseRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HealthSuite) BeforeTest(suiteName, testName string) {
|
||||||
|
mode.Set(mode.TestDev)
|
||||||
|
s.recorder = httptest.NewRecorder()
|
||||||
|
s.db = testdb.NewDB(s.T())
|
||||||
|
s.ctx, _ = gin.CreateTestContext(s.recorder)
|
||||||
|
withURL(s.ctx, "http", "example.com")
|
||||||
|
s.a = &HealthAPI{DB: s.db}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HealthSuite) AfterTest(suiteName, testName string) {
|
||||||
|
s.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HealthSuite) TestHealthSuccess() {
|
||||||
|
s.a.Health(s.ctx)
|
||||||
|
test.BodyEquals(s.T(), model.Health{Health: model.StatusGreen, Database: model.StatusGreen}, s.recorder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HealthSuite) TestDatabaseFailure() {
|
||||||
|
s.db.Close()
|
||||||
|
s.a.Health(s.ctx)
|
||||||
|
test.BodyEquals(s.T(), model.Health{Health: model.StatusOrange, Database: model.StatusRed}, s.recorder)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
// Ping pings the database to verify the connection.
|
||||||
|
func (d *GormDatabase) Ping() error {
|
||||||
|
return d.DB.DB().Ping()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *DatabaseSuite) TestPing_onValidDB() {
|
||||||
|
err := s.db.Ping()
|
||||||
|
assert.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DatabaseSuite) TestPing_onClosedDB() {
|
||||||
|
s.db.Close()
|
||||||
|
err := s.db.Ping()
|
||||||
|
assert.Error(s.T(), err)
|
||||||
|
}
|
||||||
|
|
@ -839,6 +839,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/health": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"health"
|
||||||
|
],
|
||||||
|
"summary": "Get health information.",
|
||||||
|
"operationId": "getHealth",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Ok",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Health"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Ok",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Health"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/message": {
|
"/message": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -1969,6 +1995,30 @@
|
||||||
},
|
},
|
||||||
"x-go-package": "github.com/gotify/server/model"
|
"x-go-package": "github.com/gotify/server/model"
|
||||||
},
|
},
|
||||||
|
"Health": {
|
||||||
|
"description": "Health represents how healthy the application is.",
|
||||||
|
"type": "object",
|
||||||
|
"title": "Health Model",
|
||||||
|
"required": [
|
||||||
|
"health",
|
||||||
|
"database"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"database": {
|
||||||
|
"description": "The health of the database connection.",
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Database",
|
||||||
|
"example": "green"
|
||||||
|
},
|
||||||
|
"health": {
|
||||||
|
"description": "The health of the overall application.",
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Health",
|
||||||
|
"example": "green"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "github.com/gotify/server/model"
|
||||||
|
},
|
||||||
"Message": {
|
"Message": {
|
||||||
"description": "The MessageExternal holds information about a message which was sent by an Application.",
|
"description": "The MessageExternal holds information about a message which was sent by an Application.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
// Health Model
|
||||||
|
//
|
||||||
|
// Health represents how healthy the application is.
|
||||||
|
//
|
||||||
|
// swagger:model Health
|
||||||
|
type Health struct {
|
||||||
|
// The health of the overall application.
|
||||||
|
//
|
||||||
|
// required: true
|
||||||
|
// example: green
|
||||||
|
Health string `json:"health"`
|
||||||
|
// The health of the database connection.
|
||||||
|
//
|
||||||
|
// required: true
|
||||||
|
// example: green
|
||||||
|
Database string `json:"database"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StatusGreen everything is alright.
|
||||||
|
StatusGreen = "green"
|
||||||
|
// StatusOrange some things are alright.
|
||||||
|
StatusOrange = "orange"
|
||||||
|
// StatusRed nothing is alright.
|
||||||
|
StatusRed = "red"
|
||||||
|
)
|
||||||
|
|
@ -29,6 +29,7 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
|
||||||
streamHandler := stream.New(200*time.Second, 15*time.Second, conf.Server.Stream.AllowedOrigins)
|
streamHandler := stream.New(200*time.Second, 15*time.Second, conf.Server.Stream.AllowedOrigins)
|
||||||
authentication := auth.Auth{DB: db}
|
authentication := auth.Auth{DB: db}
|
||||||
messageHandler := api.MessageAPI{Notifier: streamHandler, DB: db}
|
messageHandler := api.MessageAPI{Notifier: streamHandler, DB: db}
|
||||||
|
healthHandler := api.HealthAPI{DB: db}
|
||||||
clientHandler := api.ClientAPI{
|
clientHandler := api.ClientAPI{
|
||||||
DB: db,
|
DB: db,
|
||||||
ImageDir: conf.UploadedImagesDir,
|
ImageDir: conf.UploadedImagesDir,
|
||||||
|
|
@ -57,6 +58,7 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
|
||||||
|
|
||||||
ui.Register(g)
|
ui.Register(g)
|
||||||
|
|
||||||
|
g.GET("/health", healthHandler.Health)
|
||||||
g.GET("/swagger", docs.Serve)
|
g.GET("/swagger", docs.Serve)
|
||||||
g.Static("/image", conf.UploadedImagesDir)
|
g.Static("/image", conf.UploadedImagesDir)
|
||||||
g.GET("/docs", docs.UI)
|
g.GET("/docs", docs.UI)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue