CreateUser test
This commit is contained in:
parent
37e09d6532
commit
6d80638cf8
@ -60,7 +60,14 @@ clean:
|
|||||||
rm -rf .run-data/*
|
rm -rf .run-data/*
|
||||||
git clean -fdx
|
git clean -fdx
|
||||||
go clean
|
go clean
|
||||||
|
go clean -testcache
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
swag fmt
|
swag fmt
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test ./test/...
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,19 +38,20 @@ func NewAPIHandler(app *logic.Application) APIHandler {
|
|||||||
//
|
//
|
||||||
// @Param post_body body handler.CreateUser.body false " "
|
// @Param post_body body handler.CreateUser.body false " "
|
||||||
//
|
//
|
||||||
// @Success 200 {object} handler.sendMessageInternal.response
|
// @Success 200 {object} models.UserJSONWithClients
|
||||||
// @Failure 400 {object} ginresp.apiError
|
// @Failure 400 {object} ginresp.apiError
|
||||||
// @Failure 500 {object} ginresp.apiError
|
// @Failure 500 {object} ginresp.apiError
|
||||||
//
|
//
|
||||||
// @Router /api/users/ [POST]
|
// @Router /api/users [POST]
|
||||||
func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
|
func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
|
||||||
type body struct {
|
type body struct {
|
||||||
FCMToken string `json:"fcm_token" binding:"required"`
|
FCMToken string `json:"fcm_token"`
|
||||||
ProToken *string `json:"pro_token"`
|
ProToken *string `json:"pro_token"`
|
||||||
Username *string `json:"username"`
|
Username *string `json:"username"`
|
||||||
AgentModel string `json:"agent_model" binding:"required"`
|
AgentModel string `json:"agent_model"`
|
||||||
AgentVersion string `json:"agent_version" binding:"required"`
|
AgentVersion string `json:"agent_version"`
|
||||||
ClientType string `json:"client_type" binding:"required"`
|
ClientType string `json:"client_type"`
|
||||||
|
NoClient bool `json:"no_client"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var b body
|
var b body
|
||||||
@ -61,12 +62,23 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
defer ctx.Cancel()
|
defer ctx.Cancel()
|
||||||
|
|
||||||
var clientType models.ClientType
|
var clientType models.ClientType
|
||||||
|
if !b.NoClient {
|
||||||
|
if b.FCMToken == "" {
|
||||||
|
return ginresp.APIError(g, 400, apierr.INVALID_CLIENTTYPE, "Missing FCMToken", nil)
|
||||||
|
}
|
||||||
|
if b.AgentVersion == "" {
|
||||||
|
return ginresp.APIError(g, 400, apierr.INVALID_CLIENTTYPE, "Missing AgentVersion", nil)
|
||||||
|
}
|
||||||
|
if b.ClientType == "" {
|
||||||
|
return ginresp.APIError(g, 400, apierr.INVALID_CLIENTTYPE, "Missing ClientType", nil)
|
||||||
|
}
|
||||||
if b.ClientType == string(models.ClientTypeAndroid) {
|
if b.ClientType == string(models.ClientTypeAndroid) {
|
||||||
clientType = models.ClientTypeAndroid
|
clientType = models.ClientTypeAndroid
|
||||||
} else if b.ClientType == string(models.ClientTypeIOS) {
|
} else if b.ClientType == string(models.ClientTypeIOS) {
|
||||||
clientType = models.ClientTypeIOS
|
clientType = models.ClientTypeIOS
|
||||||
} else {
|
} else {
|
||||||
return ginresp.APIError(g, 400, apierr.INVALID_CLIENTTYPE, "Invalid ClientType", nil)
|
return ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Invalid ClientType", nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.ProToken != nil {
|
if b.ProToken != nil {
|
||||||
@ -106,12 +118,17 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create user in db", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create user in db", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.database.CreateClient(ctx, userobj.UserID, clientType, b.FCMToken, b.AgentModel, b.AgentVersion)
|
if b.NoClient {
|
||||||
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients(make([]models.Client, 0))))
|
||||||
|
} else {
|
||||||
|
client, err := h.database.CreateClient(ctx, userobj.UserID, clientType, b.FCMToken, b.AgentModel, b.AgentVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create user in db", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create client in db", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients([]models.Client{client})))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSON()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUser swaggerdoc
|
// GetUser swaggerdoc
|
||||||
@ -409,7 +426,7 @@ func (h APIHandler) AddClient(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
client, err := h.database.CreateClient(ctx, u.UserID, clientType, b.FCMToken, b.AgentModel, b.AgentVersion)
|
client, err := h.database.CreateClient(ctx, u.UserID, clientType, b.FCMToken, b.AgentModel, b.AgentVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create user in db", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create client in db", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, client.JSON()))
|
||||||
|
@ -5,9 +5,11 @@ import (
|
|||||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
sqlite3 "github.com/mattn/go-sqlite3"
|
sqlite3 "github.com/mattn/go-sqlite3"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/timeext"
|
"gogs.mikescher.com/BlackForestBytes/goext/timeext"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@ -74,7 +76,7 @@ func (h CommonHandler) Ping(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
// @Success 200 {object} handler.DatabaseTest.response
|
// @Success 200 {object} handler.DatabaseTest.response
|
||||||
// @Failure 500 {object} ginresp.apiError
|
// @Failure 500 {object} ginresp.apiError
|
||||||
//
|
//
|
||||||
// @Router /api/db-test [get]
|
// @Router /api/db-test [post]
|
||||||
func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
|
func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
|
||||||
type response struct {
|
type response struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
@ -113,6 +115,9 @@ func (h CommonHandler) Health(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
_, libVersionNumber, _ := sqlite3.Version()
|
_, libVersionNumber, _ := sqlite3.Version()
|
||||||
|
|
||||||
if libVersionNumber < 3039000 {
|
if libVersionNumber < 3039000 {
|
||||||
@ -124,6 +129,28 @@ func (h CommonHandler) Health(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.InternalError(err)
|
return ginresp.InternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uuidKey, _ := langext.NewHexUUID()
|
||||||
|
uuidWrite, _ := langext.NewHexUUID()
|
||||||
|
|
||||||
|
err = h.app.Database.WriteMetaString(ctx, uuidKey, uuidWrite)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uuidRead, err := h.app.Database.ReadMetaString(ctx, uuidKey)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uuidRead == nil || uuidWrite != *uuidRead {
|
||||||
|
return ginresp.InternalError(errors.New("writing into DB was not consistent"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.app.Database.DeleteMeta(ctx, uuidKey)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
return ginresp.JSON(http.StatusOK, response{Status: "ok"})
|
return ginresp.JSON(http.StatusOK, response{Status: "ok"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
_, err = h.database.CreateClient(ctx, user.UserID, models.ClientTypeAndroid, *data.FCMToken, "compat", "compat")
|
_, err = h.database.CreateClient(ctx, user.UserID, models.ClientTypeAndroid, *data.FCMToken, "compat", "compat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.CompatAPIError(0, "Failed to create user in db")
|
return ginresp.CompatAPIError(0, "Failed to create client in db")
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||||
|
@ -35,6 +35,11 @@ func (db *Database) Migrate(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.WriteMetaInt(ctx, "schema", 3)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
} else if currschema == 1 {
|
} else if currschema == 1 {
|
||||||
@ -49,34 +54,6 @@ func (db *Database) Migrate(ctx context.Context) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) ReadSchema(ctx context.Context) (int, error) {
|
|
||||||
|
|
||||||
r1, err := db.db.QueryContext(ctx, "SELECT name FROM sqlite_master WHERE type='table' AND name='meta'")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !r1.Next() {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r2, err := db.db.QueryContext(ctx, "SELECT value_int FROM meta WHERE meta_key='schema'")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if !r2.Next() {
|
|
||||||
return 0, errors.New("no schema entry in meta table")
|
|
||||||
}
|
|
||||||
|
|
||||||
var dbschema int
|
|
||||||
err = r2.Scan(&dbschema)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbschema, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *Database) Ping() error {
|
func (db *Database) Ping() error {
|
||||||
return db.db.Ping()
|
return db.db.Ping()
|
||||||
}
|
}
|
||||||
|
159
server/db/meta.go
Normal file
159
server/db/meta.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (db *Database) ReadSchema(ctx context.Context) (int, error) {
|
||||||
|
|
||||||
|
r1, err := db.db.QueryContext(ctx, "SELECT name FROM sqlite_master WHERE type='table' AND name='meta'")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r1.Next() {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
r2, err := db.db.QueryContext(ctx, "SELECT value_int FROM meta WHERE meta_key='schema'")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if !r2.Next() {
|
||||||
|
return 0, errors.New("no schema entry in meta table")
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbschema int
|
||||||
|
err = r2.Scan(&dbschema)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbschema, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) WriteMetaString(ctx context.Context, key string, value string) error {
|
||||||
|
_, err := db.db.ExecContext(ctx, "INSERT INTO meta (meta_key, value_txt) VALUES (?, ?) ON CONFLICT(meta_key) DO UPDATE SET value_txt = ?",
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) WriteMetaInt(ctx context.Context, key string, value int64) error {
|
||||||
|
_, err := db.db.ExecContext(ctx, "INSERT INTO meta (meta_key, value_int) VALUES (?, ?) ON CONFLICT(meta_key) DO UPDATE SET value_int = ?",
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) WriteMetaReal(ctx context.Context, key string, value float64) error {
|
||||||
|
_, err := db.db.ExecContext(ctx, "INSERT INTO meta (meta_key, value_real) VALUES (?, ?) ON CONFLICT(meta_key) DO UPDATE SET value_real = ?",
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) WriteMetaBlob(ctx context.Context, key string, value []byte) error {
|
||||||
|
_, err := db.db.ExecContext(ctx, "INSERT INTO meta (meta_key, value_blob) VALUES (?, ?) ON CONFLICT(meta_key) DO UPDATE SET value_blob = ?",
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ReadMetaString(ctx context.Context, key string) (*string, error) {
|
||||||
|
r2, err := db.db.QueryContext(ctx, "SELECT value_txt FROM meta WHERE meta_key=?", key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !r2.Next() {
|
||||||
|
return nil, errors.New("no matching entry in meta table")
|
||||||
|
}
|
||||||
|
|
||||||
|
var value string
|
||||||
|
err = r2.Scan(&value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return langext.Ptr(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ReadMetaInt(ctx context.Context, key string) (*int64, error) {
|
||||||
|
r2, err := db.db.QueryContext(ctx, "SELECT value_int FROM meta WHERE meta_key=?", key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !r2.Next() {
|
||||||
|
return nil, errors.New("no matching entry in meta table")
|
||||||
|
}
|
||||||
|
|
||||||
|
var value int64
|
||||||
|
err = r2.Scan(&value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return langext.Ptr(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ReadMetaReal(ctx context.Context, key string) (*float64, error) {
|
||||||
|
r2, err := db.db.QueryContext(ctx, "SELECT value_real FROM meta WHERE meta_key=?", key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !r2.Next() {
|
||||||
|
return nil, errors.New("no matching entry in meta table")
|
||||||
|
}
|
||||||
|
|
||||||
|
var value float64
|
||||||
|
err = r2.Scan(&value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return langext.Ptr(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ReadMetaBlob(ctx context.Context, key string) (*[]byte, error) {
|
||||||
|
r2, err := db.db.QueryContext(ctx, "SELECT value_blob FROM meta WHERE meta_key=?", key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !r2.Next() {
|
||||||
|
return nil, errors.New("no matching entry in meta table")
|
||||||
|
}
|
||||||
|
|
||||||
|
var value []byte
|
||||||
|
err = r2.Scan(&value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return langext.Ptr(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteMeta(ctx context.Context, key string) error {
|
||||||
|
_, err := db.db.ExecContext(ctx, "DELETE FROM meta WHERE meta_key = ?", key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -125,4 +125,6 @@ CREATE TABLE `meta`
|
|||||||
|
|
||||||
PRIMARY KEY (meta_key)
|
PRIMARY KEY (meta_key)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO meta (meta_key, value_int) VALUES ('schema', 3)
|
INSERT INTO meta (meta_key, value_int) VALUES ('schema', 3)
|
@ -167,7 +167,7 @@ func (app *Application) StartRequest(g *gin.Context, uri any, query any, body an
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if body != nil && g.Request.Header.Get("Content-Type") == "application/javascript" {
|
if body != nil && g.Request.Header.Get("Content-Type") == "application/json" {
|
||||||
if err := g.ShouldBindJSON(body); err != nil {
|
if err := g.ShouldBindJSON(body); err != nil {
|
||||||
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read body", err))
|
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read body", err))
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,13 @@ func (u User) JSON() UserJSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u User) JSONWithClients(clients []Client) UserJSONWithClients {
|
||||||
|
return UserJSONWithClients{
|
||||||
|
UserJSON: u.JSON(),
|
||||||
|
Clients: langext.ArrMap(clients, func(v Client) ClientJSON { return v.JSON() }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (u User) MaxContentLength() int {
|
func (u User) MaxContentLength() int {
|
||||||
if u.IsPro {
|
if u.IsPro {
|
||||||
return 16384
|
return 16384
|
||||||
@ -99,6 +106,11 @@ type UserJSON struct {
|
|||||||
DefaultChannel string `json:"default_channel"`
|
DefaultChannel string `json:"default_channel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserJSONWithClients struct {
|
||||||
|
UserJSON
|
||||||
|
Clients []ClientJSON `json:"clients"`
|
||||||
|
}
|
||||||
|
|
||||||
type UserDB struct {
|
type UserDB struct {
|
||||||
UserID UserID `db:"user_id"`
|
UserID UserID `db:"user_id"`
|
||||||
Username *string `db:"username"`
|
Username *string `db:"username"`
|
||||||
|
@ -1034,7 +1034,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/handler.sendMessageInternal.response"
|
"$ref": "#/definitions/models.UserJSONWithClients"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@ -2945,6 +2945,56 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"models.UserJSONWithClients": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"admin_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"clients": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.ClientJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default_channel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"is_pro": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"messages_sent": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"quota_used": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"quota_used_day": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"read_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"send_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp_created": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp_last_read": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp_last_sent": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
|
@ -442,6 +442,39 @@ definitions:
|
|||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.UserJSONWithClients:
|
||||||
|
properties:
|
||||||
|
admin_key:
|
||||||
|
type: string
|
||||||
|
clients:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.ClientJSON'
|
||||||
|
type: array
|
||||||
|
default_channel:
|
||||||
|
type: string
|
||||||
|
is_pro:
|
||||||
|
type: boolean
|
||||||
|
messages_sent:
|
||||||
|
type: integer
|
||||||
|
quota_used:
|
||||||
|
type: integer
|
||||||
|
quota_used_day:
|
||||||
|
type: string
|
||||||
|
read_key:
|
||||||
|
type: string
|
||||||
|
send_key:
|
||||||
|
type: string
|
||||||
|
timestamp_created:
|
||||||
|
type: string
|
||||||
|
timestamp_last_read:
|
||||||
|
type: string
|
||||||
|
timestamp_last_sent:
|
||||||
|
type: string
|
||||||
|
user_id:
|
||||||
|
type: integer
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
host: scn.blackforestbytes.com
|
host: scn.blackforestbytes.com
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
@ -1142,7 +1175,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/handler.sendMessageInternal.response'
|
$ref: '#/definitions/models.UserJSONWithClients'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
|
@ -10,26 +10,65 @@ import (
|
|||||||
"blackforestbytes.com/simplecloudnotifier/push"
|
"blackforestbytes.com/simplecloudnotifier/push"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewSimpleWebserver(t *testing.T) *logic.Application {
|
type Void = struct{}
|
||||||
|
|
||||||
uuid, err := langext.NewHexUUID()
|
func NewSimpleWebserver() (*logic.Application, func()) {
|
||||||
|
cw := zerolog.ConsoleWriter{
|
||||||
|
Out: os.Stdout,
|
||||||
|
TimeFormat: "2006-01-02 15:04:05 Z07:00",
|
||||||
|
}
|
||||||
|
|
||||||
|
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||||
|
multi := zerolog.MultiLevelWriter(cw)
|
||||||
|
logger := zerolog.New(multi).With().
|
||||||
|
Timestamp().
|
||||||
|
Caller().
|
||||||
|
Logger()
|
||||||
|
|
||||||
|
log.Logger = logger
|
||||||
|
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||||
|
|
||||||
|
uuid1, _ := langext.NewHexUUID()
|
||||||
|
uuid2, _ := langext.NewHexUUID()
|
||||||
|
dbdir := filepath.Join(os.TempDir(), uuid1)
|
||||||
|
dbfile := filepath.Join(dbdir, uuid2+".sqlite3")
|
||||||
|
|
||||||
|
err := os.MkdirAll(dbdir, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbfile := filepath.Join(os.TempDir(), uuid+"sqlite3")
|
f, err := os.Create(dbfile)
|
||||||
defer func() {
|
if err != nil {
|
||||||
_ = os.Remove(dbfile)
|
panic(err)
|
||||||
}()
|
}
|
||||||
|
err = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(dbfile, 0777)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//dbfile := "/home/mike/Code/private/SimpleCloudNotifier/server/.run-data/db_test.sqlite3"
|
||||||
|
|
||||||
|
fmt.Println("DatabaseFile: " + dbfile)
|
||||||
|
|
||||||
conf := scn.Config{
|
conf := scn.Config{
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
@ -64,39 +103,94 @@ func NewSimpleWebserver(t *testing.T) *logic.Application {
|
|||||||
|
|
||||||
router.Init(ginengine)
|
router.Init(ginengine)
|
||||||
|
|
||||||
return app
|
return app, func() { app.Stop(); _ = os.Remove(dbfile) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestGet[T any](t *testing.T, baseURL string, prefix string) T {
|
func requestGet[TResult any](baseURL string, prefix string) TResult {
|
||||||
|
return requestAny[TResult]("", "GET", baseURL, prefix, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAuthGet[TResult any](akey string, baseURL string, prefix string) TResult {
|
||||||
|
return requestAny[TResult](akey, "GET", baseURL, prefix, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestPost[TResult any](baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult]("", "POST", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAuthPost[TResult any](akey string, baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult](akey, "POST", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestPut[TResult any](baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult]("", "PUT", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAuthPUT[TResult any](akey string, baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult](akey, "PUT", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestPatch[TResult any](baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult]("", "PATCH", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAuthPatch[TResult any](akey string, baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult](akey, "PATCH", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestDelete[TResult any](baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult]("", "DELETE", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAuthDelete[TResult any](akey string, baseURL string, prefix string, body any) TResult {
|
||||||
|
return requestAny[TResult](akey, "DELETE", baseURL, prefix, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestAny[TResult any](akey string, method string, baseURL string, prefix string, body any) TResult {
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", baseURL+prefix, bytes.NewReader([]byte{}))
|
bytesbody := make([]byte, 0)
|
||||||
|
if body != nil {
|
||||||
|
bjson, err := json.Marshal(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
panic(err)
|
||||||
return *new(T)
|
}
|
||||||
|
bytesbody = bjson
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, baseURL+prefix, bytes.NewReader(bytesbody))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
if akey != "" {
|
||||||
|
req.Header.Set("Authorization", "SCN "+akey)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
panic(err)
|
||||||
return *new(T)
|
|
||||||
}
|
}
|
||||||
defer func() { _ = resp.Body.Close() }()
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
t.Error("Statuscode != 200")
|
|
||||||
}
|
|
||||||
|
|
||||||
respBodyBin, err := io.ReadAll(resp.Body)
|
respBodyBin, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
panic(err)
|
||||||
return *new(T)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var data T
|
if resp.StatusCode != 200 {
|
||||||
|
fmt.Println("Request: " + method + " :: " + baseURL + prefix)
|
||||||
|
fmt.Println(string(respBodyBin))
|
||||||
|
panic("Statuscode != 200")
|
||||||
|
}
|
||||||
|
|
||||||
|
var data TResult
|
||||||
if err := json.Unmarshal(respBodyBin, &data); err != nil {
|
if err := json.Unmarshal(respBodyBin, &data); err != nil {
|
||||||
t.Error(err)
|
panic(err)
|
||||||
return *new(T)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
29
server/test/user_test.go
Normal file
29
server/test/user_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateUserNoClient(t *testing.T) {
|
||||||
|
ws, stop := NewSimpleWebserver()
|
||||||
|
defer stop()
|
||||||
|
go func() { ws.Run() }()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
baseUrl := "http://127.0.0.1:" + ws.Port
|
||||||
|
|
||||||
|
res := requestPost[gin.H](baseUrl, "/api/users", gin.H{
|
||||||
|
"no_client": true,
|
||||||
|
})
|
||||||
|
|
||||||
|
uid := fmt.Sprintf("%v", res["user_id"])
|
||||||
|
admintok := res["admin_key"].(string)
|
||||||
|
|
||||||
|
fmt.Printf("uid := %s\n", uid)
|
||||||
|
fmt.Printf("admin_key := %s\n", admintok)
|
||||||
|
|
||||||
|
requestAuthGet[Void](admintok, baseUrl, "/api/users/"+uid)
|
||||||
|
}
|
@ -6,20 +6,45 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestWebserver(t *testing.T) {
|
func TestWebserver(t *testing.T) {
|
||||||
ws := NewSimpleWebserver(t)
|
ws, stop := NewSimpleWebserver()
|
||||||
defer ws.Stop()
|
defer stop()
|
||||||
go func() { ws.Run() }()
|
go func() { ws.Run() }()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPing(t *testing.T) {
|
func TestPing(t *testing.T) {
|
||||||
ws := NewSimpleWebserver(t)
|
ws, stop := NewSimpleWebserver()
|
||||||
defer ws.Stop()
|
defer stop()
|
||||||
go func() { ws.Run() }()
|
go func() { ws.Run() }()
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
baseUrl := "http://127.0.0.1:" + ws.Port
|
baseUrl := "http://127.0.0.1:" + ws.Port
|
||||||
|
|
||||||
_ = requestGet[struct{}](t, baseUrl, "/api/ping")
|
_ = requestGet[Void](baseUrl, "/api/ping")
|
||||||
|
_ = requestPut[Void](baseUrl, "/api/ping", nil)
|
||||||
|
_ = requestPost[Void](baseUrl, "/api/ping", nil)
|
||||||
|
_ = requestPatch[Void](baseUrl, "/api/ping", nil)
|
||||||
|
_ = requestDelete[Void](baseUrl, "/api/ping", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMongo(t *testing.T) {
|
||||||
|
ws, stop := NewSimpleWebserver()
|
||||||
|
defer stop()
|
||||||
|
go func() { ws.Run() }()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
baseUrl := "http://127.0.0.1:" + ws.Port
|
||||||
|
|
||||||
|
_ = requestPost[Void](baseUrl, "/api/db-test", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHealth(t *testing.T) {
|
||||||
|
ws, stop := NewSimpleWebserver()
|
||||||
|
defer stop()
|
||||||
|
go func() { ws.Run() }()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
baseUrl := "http://127.0.0.1:" + ws.Port
|
||||||
|
|
||||||
|
_ = requestGet[Void](baseUrl, "/api/health")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user