Tests[RequestLogSimple]
This commit is contained in:
parent
b2df0a5a02
commit
03f60ff316
@ -77,6 +77,8 @@
|
||||
|
||||
- Pagination for ListChannels / ListSubscriptions / ListClients / ListChannelSubscriptions / ListUserSubscriptions
|
||||
|
||||
- Add .Insert() function to sq.DB interface (auto generate insert for an object based on struct keys)
|
||||
|
||||
- cannot open sqlite in dbbrowsr (cannot parse schema?)
|
||||
-> https://github.com/sqlitebrowser/sqlitebrowser/issues/292 -> https://github.com/sqlitebrowser/sqlitebrowser/issues/29266
|
||||
|
||||
|
@ -124,7 +124,7 @@ func createRequestLog(g *gin.Context, t0 time.Time, ctr int, resp HTTPResponse,
|
||||
RequestBodySize: int64(len(reqbody)),
|
||||
RequestContentType: ct,
|
||||
RemoteIP: g.RemoteIP(),
|
||||
TokenID: langext.ConditionalFn10(hasTok, func() *models.KeyTokenID { return langext.Ptr(permObj.(models.PermissionSet).Token.KeyTokenID) }, nil),
|
||||
KeyID: langext.ConditionalFn10(hasTok, func() *models.KeyTokenID { return langext.Ptr(permObj.(models.PermissionSet).Token.KeyTokenID) }, nil),
|
||||
UserID: langext.ConditionalFn10(hasTok, func() *models.UserID { return langext.Ptr(permObj.(models.PermissionSet).Token.OwnerUserID) }, nil),
|
||||
Permissions: langext.ConditionalFn10(hasTok, func() *string { return langext.Ptr(permObj.(models.PermissionSet).Token.Permissions.String()) }, nil),
|
||||
ResponseStatuscode: langext.ConditionalFn10(resp != nil, func() *int64 { return langext.Ptr(int64(resp.Statuscode())) }, nil),
|
||||
|
@ -900,7 +900,7 @@ func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||
ChannelID: langext.Ptr([]models.ChannelID{channel.ChannelID}),
|
||||
}
|
||||
|
||||
messages, npt, err := h.database.ListMessages(ctx, filter, pageSize, tok)
|
||||
messages, npt, err := h.database.ListMessages(ctx, filter, &pageSize, tok)
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query messages", err)
|
||||
}
|
||||
@ -1398,7 +1398,7 @@ func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||
filter.SearchString = langext.Ptr([]string{strings.TrimSpace(*q.Filter)})
|
||||
}
|
||||
|
||||
messages, npt, err := h.database.ListMessages(ctx, filter, pageSize, tok)
|
||||
messages, npt, err := h.database.ListMessages(ctx, filter, &pageSize, tok)
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query messages", err)
|
||||
}
|
||||
@ -1561,7 +1561,7 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
|
||||
UserID models.UserID `uri:"uid" binding:"entityid"`
|
||||
}
|
||||
type response struct {
|
||||
Tokens []models.KeyTokenJSON `json:"tokens"`
|
||||
Keys []models.KeyTokenJSON `json:"keys"`
|
||||
}
|
||||
|
||||
var u uri
|
||||
@ -1582,7 +1582,7 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
|
||||
|
||||
res := langext.ArrMap(clients, func(v models.KeyToken) models.KeyTokenJSON { return v.JSON() })
|
||||
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Tokens: res}))
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Keys: res}))
|
||||
}
|
||||
|
||||
// GetUserKey swaggerdoc
|
||||
|
@ -527,7 +527,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
CompatAcknowledged: langext.Ptr(false),
|
||||
}
|
||||
|
||||
msgs, _, err := h.database.ListMessages(ctx, filter, 16, ct.Start())
|
||||
msgs, _, err := h.database.ListMessages(ctx, filter, langext.Ptr(16), ct.Start())
|
||||
if err != nil {
|
||||
return ginresp.CompatAPIError(0, "Failed to query user")
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ func (db *Database) DeleteMessage(ctx TxContext, messageID models.MessageID) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pageSize int, inTok ct.CursorToken) ([]models.Message, ct.CursorToken, error) {
|
||||
func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pageSize *int, inTok ct.CursorToken) ([]models.Message, ct.CursorToken, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, ct.CursorToken{}, err
|
||||
@ -135,11 +135,16 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
||||
|
||||
filterCond, filterJoin, prepParams, err := filter.SQL()
|
||||
|
||||
orderClause := "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC, message_id DESC LIMIT :lim"
|
||||
orderClause := ""
|
||||
if pageSize != nil {
|
||||
orderClause = "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC, message_id DESC LIMIT :lim"
|
||||
prepParams["lim"] = *pageSize + 1
|
||||
} else {
|
||||
orderClause = "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC, message_id DESC"
|
||||
}
|
||||
|
||||
sqlQuery := "SELECT " + "messages.*" + " FROM messages " + filterJoin + " WHERE ( " + pageCond + " ) AND ( " + filterCond + " ) " + orderClause
|
||||
|
||||
prepParams["lim"] = pageSize + 1
|
||||
prepParams["tokts"] = inTok.Timestamp
|
||||
prepParams["tokid"] = inTok.Id
|
||||
|
||||
@ -153,10 +158,10 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
if len(data) <= pageSize {
|
||||
if pageSize == nil || len(data) <= *pageSize {
|
||||
return data, ct.End(), nil
|
||||
} else {
|
||||
outToken := ct.Normal(data[pageSize-1].Timestamp(), data[pageSize-1].MessageID.String(), "DESC", filter.Hash())
|
||||
return data[0:pageSize], outToken, nil
|
||||
outToken := ct.Normal(data[*pageSize-1].Timestamp(), data[*pageSize-1].MessageID.String(), "DESC", filter.Hash())
|
||||
return data[0:*pageSize], outToken, nil
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"context"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
@ -11,7 +12,7 @@ func (db *Database) InsertRequestLog(ctx context.Context, requestid models.Reque
|
||||
|
||||
now := time.Now()
|
||||
|
||||
_, err := db.db.Exec(ctx, "INSERT INTO requests (request_id, method, uri, user_agent, authentication, request_body, request_body_size, request_content_type, remote_ip, userid, permissions, response_statuscode, response_body_size, response_body, response_content_type, retry_count, panicked, panic_str, processing_time, timestamp_created, timestamp_start, timestamp_finish) VALUES (:request_id, :method, :uri, :user_agent, :authentication, :request_body, :request_body_size, :request_content_type, :remote_ip, :userid, :permissions, :response_statuscode, :response_body_size, :response_body, :response_content_type, :retry_count, :panicked, :panic_str, :processing_time, :timestamp_created, :timestamp_start, :timestamp_finish)", sq.PP{
|
||||
_, err := db.db.Exec(ctx, "INSERT INTO requests (request_id, method, uri, user_agent, authentication, request_body, request_body_size, request_content_type, remote_ip, userid, permissions, response_statuscode, response_body_size, response_body, response_content_type, retry_count, panicked, panic_str, processing_time, timestamp_created, timestamp_start, timestamp_finish, key_id) VALUES (:request_id, :method, :uri, :user_agent, :authentication, :request_body, :request_body_size, :request_content_type, :remote_ip, :userid, :permissions, :response_statuscode, :response_body_size, :response_body, :response_content_type, :retry_count, :panicked, :panic_str, :processing_time, :timestamp_created, :timestamp_start, :timestamp_finish, :kid)", sq.PP{
|
||||
"request_id": requestid,
|
||||
"method": data.Method,
|
||||
"uri": data.URI,
|
||||
@ -34,6 +35,7 @@ func (db *Database) InsertRequestLog(ctx context.Context, requestid models.Reque
|
||||
"timestamp_created": now.UnixMilli(),
|
||||
"timestamp_start": data.TimestampStart,
|
||||
"timestamp_finish": data.TimestampFinish,
|
||||
"kid": data.KeyID,
|
||||
})
|
||||
if err != nil {
|
||||
return models.RequestLogDB{}, err
|
||||
@ -62,6 +64,7 @@ func (db *Database) InsertRequestLog(ctx context.Context, requestid models.Reque
|
||||
TimestampCreated: now.UnixMilli(),
|
||||
TimestampStart: data.TimestampStart,
|
||||
TimestampFinish: data.TimestampFinish,
|
||||
KeyID: data.KeyID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -90,3 +93,46 @@ func (db *Database) Cleanup(ctx context.Context, count int, duration time.Durati
|
||||
|
||||
return affected1 + affected2, nil
|
||||
}
|
||||
|
||||
func (db *Database) ListRequestLogs(ctx context.Context, filter models.RequestLogFilter, pageSize *int, inTok ct.CursorToken) ([]models.RequestLog, ct.CursorToken, error) {
|
||||
if inTok.Mode == ct.CTMEnd {
|
||||
return make([]models.RequestLog, 0), ct.End(), nil
|
||||
}
|
||||
|
||||
pageCond := "1=1"
|
||||
if inTok.Mode == ct.CTMNormal {
|
||||
pageCond = "timestamp_created < :tokts OR (timestamp_created = :tokts AND request_id < :tokid )"
|
||||
}
|
||||
|
||||
filterCond, filterJoin, prepParams, err := filter.SQL()
|
||||
|
||||
orderClause := ""
|
||||
if pageSize != nil {
|
||||
orderClause = "ORDER BY timestamp_created DESC, request_id DESC LIMIT :lim"
|
||||
prepParams["lim"] = *pageSize + 1
|
||||
} else {
|
||||
orderClause = "ORDER BY timestamp_created DESC, request_id DESC"
|
||||
}
|
||||
|
||||
sqlQuery := "SELECT " + "requests.*" + " FROM requests " + filterJoin + " WHERE ( " + pageCond + " ) AND ( " + filterCond + " ) " + orderClause
|
||||
|
||||
prepParams["tokts"] = inTok.Timestamp
|
||||
prepParams["tokid"] = inTok.Id
|
||||
|
||||
rows, err := db.db.Query(ctx, sqlQuery, prepParams)
|
||||
if err != nil {
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
data, err := models.DecodeRequestLogs(rows)
|
||||
if err != nil {
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
if pageSize == nil || len(data) <= *pageSize {
|
||||
return data, ct.End(), nil
|
||||
} else {
|
||||
outToken := ct.Normal(data[*pageSize-1].TimestampCreated, data[*pageSize-1].RequestID.String(), "DESC", filter.Hash())
|
||||
return data[0:*pageSize], outToken, nil
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ CREATE TABLE `requests`
|
||||
request_body_size INTEGER NOT NULL,
|
||||
request_content_type TEXT NOT NULL,
|
||||
remote_ip TEXT NOT NULL,
|
||||
key_id TEXT NULL,
|
||||
|
||||
userid TEXT NULL,
|
||||
permissions TEXT NULL,
|
||||
|
@ -18,7 +18,7 @@ type RequestLog struct {
|
||||
RequestBodySize int64
|
||||
RequestContentType string
|
||||
RemoteIP string
|
||||
TokenID *KeyTokenID
|
||||
KeyID *KeyTokenID
|
||||
UserID *UserID
|
||||
Permissions *string
|
||||
ResponseStatuscode *int64
|
||||
@ -45,7 +45,7 @@ func (c RequestLog) JSON() RequestLogJSON {
|
||||
RequestBodySize: c.RequestBodySize,
|
||||
RequestContentType: c.RequestContentType,
|
||||
RemoteIP: c.RemoteIP,
|
||||
TokenID: c.TokenID,
|
||||
KeyID: c.KeyID,
|
||||
UserID: c.UserID,
|
||||
Permissions: c.Permissions,
|
||||
ResponseStatuscode: c.ResponseStatuscode,
|
||||
@ -73,7 +73,7 @@ func (c RequestLog) DB() RequestLogDB {
|
||||
RequestBodySize: c.RequestBodySize,
|
||||
RequestContentType: c.RequestContentType,
|
||||
RemoteIP: c.RemoteIP,
|
||||
TokenID: c.TokenID,
|
||||
KeyID: c.KeyID,
|
||||
UserID: c.UserID,
|
||||
Permissions: c.Permissions,
|
||||
ResponseStatuscode: c.ResponseStatuscode,
|
||||
@ -100,7 +100,7 @@ type RequestLogJSON struct {
|
||||
RequestBodySize int64 `json:"request_body_size"`
|
||||
RequestContentType string `json:"request_content_type"`
|
||||
RemoteIP string `json:"remote_ip"`
|
||||
TokenID *KeyTokenID `json:"token_id"`
|
||||
KeyID *KeyTokenID `json:"key_id"`
|
||||
UserID *UserID `json:"userid"`
|
||||
Permissions *string `json:"permissions"`
|
||||
ResponseStatuscode *int64 `json:"response_statuscode"`
|
||||
@ -117,7 +117,7 @@ type RequestLogJSON struct {
|
||||
}
|
||||
|
||||
type RequestLogDB struct {
|
||||
RequestID RequestID `db:"requestLog_id"`
|
||||
RequestID RequestID `db:"request_id"`
|
||||
Method string `db:"method"`
|
||||
URI string `db:"uri"`
|
||||
UserAgent *string `db:"user_agent"`
|
||||
@ -126,13 +126,13 @@ type RequestLogDB struct {
|
||||
RequestBodySize int64 `db:"request_body_size"`
|
||||
RequestContentType string `db:"request_content_type"`
|
||||
RemoteIP string `db:"remote_ip"`
|
||||
TokenID *KeyTokenID `db:"token_id"`
|
||||
KeyID *KeyTokenID `db:"key_id"`
|
||||
UserID *UserID `db:"userid"`
|
||||
Permissions *string `db:"permissions"`
|
||||
ResponseStatuscode *int64 `db:"response_statuscode"`
|
||||
ResponseBodySize *int64 `db:"response_body_size"`
|
||||
ResponseBody *string `db:"response_body"`
|
||||
ResponseContentType string `db:"request_content_type"`
|
||||
ResponseContentType string `db:"response_content_type"`
|
||||
RetryCount int64 `db:"retry_count"`
|
||||
Panicked int64 `db:"panicked"`
|
||||
PanicStr *string `db:"panic_str"`
|
||||
@ -153,6 +153,7 @@ func (c RequestLogDB) Model() RequestLog {
|
||||
RequestBodySize: c.RequestBodySize,
|
||||
RequestContentType: c.RequestContentType,
|
||||
RemoteIP: c.RemoteIP,
|
||||
KeyID: c.KeyID,
|
||||
UserID: c.UserID,
|
||||
Permissions: c.Permissions,
|
||||
ResponseStatuscode: c.ResponseStatuscode,
|
||||
|
45
scnserver/models/requestlogfilter.go
Normal file
45
scnserver/models/requestlogfilter.go
Normal file
@ -0,0 +1,45 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RequestLogFilter struct {
|
||||
}
|
||||
|
||||
func (f RequestLogFilter) SQL() (string, string, sq.PP, error) {
|
||||
|
||||
joinClause := ""
|
||||
|
||||
// ...
|
||||
|
||||
sqlClauses := make([]string, 0)
|
||||
|
||||
params := sq.PP{}
|
||||
|
||||
// ...
|
||||
|
||||
sqlClause := ""
|
||||
if len(sqlClauses) > 0 {
|
||||
sqlClause = strings.Join(sqlClauses, " AND ")
|
||||
} else {
|
||||
sqlClause = "1=1"
|
||||
}
|
||||
|
||||
return sqlClause, joinClause, params, nil
|
||||
}
|
||||
|
||||
func (f RequestLogFilter) Hash() string {
|
||||
bh, err := dataext.StructHash(f, dataext.StructHashOptions{HashAlgo: sha512.New()})
|
||||
if err != nil {
|
||||
return "00000000"
|
||||
}
|
||||
|
||||
str := hex.EncodeToString(bh)
|
||||
return str[0:mathext.Min(8, len(bh))]
|
||||
}
|
56
scnserver/test/keytoken_test.go
Normal file
56
scnserver/test/keytoken_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListUserKeys(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
data := tt.InitSingleData(t, ws)
|
||||
|
||||
type keylist struct {
|
||||
Tokens []struct {
|
||||
AllChannels bool `json:"all_channels"`
|
||||
Channels []string `json:"channels"`
|
||||
KeytokenId string `json:"keytoken_id"`
|
||||
MessagesSent int `json:"messages_sent"`
|
||||
Name string `json:"name"`
|
||||
OwnerUserId string `json:"owner_user_id"`
|
||||
Permissions string `json:"permissions"`
|
||||
} `json:"tokens"`
|
||||
}
|
||||
|
||||
klist := tt.RequestAuthGet[keylist](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UserID))
|
||||
|
||||
tt.AssertEqual(t, "len(keys)", 1, len(klist.Tokens))
|
||||
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestCreateUserKey(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestDeleteUserKey(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestGetUserKey(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestUpdateUserKey(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestUserKeyPermissions(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestUsedKeyInMessage(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
@ -1,3 +1,126 @@
|
||||
package test
|
||||
|
||||
//TODO test requestlog
|
||||
import (
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRequestLogSimple(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
ctx := ws.NewSimpleTransactionContext(5 * time.Second)
|
||||
defer ctx.Cancel()
|
||||
|
||||
// Ping
|
||||
{
|
||||
tt.RequestGet[tt.Void](t, baseUrl, fmt.Sprintf("/api/ping"))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
rl, _, err := ws.Database.Requests.ListRequestLogs(ctx, models.RequestLogFilter{}, nil, ct.Start())
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
tt.AssertEqual(t, "requestlog.count", 1, len(rl))
|
||||
|
||||
tt.AssertEqual(t, "requestlog[0].Method", "GET", rl[0].Method)
|
||||
tt.AssertEqual(t, "requestlog[0].KeyID", nil, rl[0].KeyID)
|
||||
tt.AssertEqual(t, "requestlog[0].UserID", nil, rl[0].UserID)
|
||||
tt.AssertEqual(t, "requestlog[0].Panicked", false, rl[0].Panicked)
|
||||
tt.AssertEqual(t, "requestlog[0].URI", "/api/ping", rl[0].URI)
|
||||
tt.AssertEqual(t, "requestlog[0].ResponseContentType", "application/json", rl[0].ResponseContentType)
|
||||
}
|
||||
|
||||
// HTMl request
|
||||
{
|
||||
tt.RequestRaw(t, baseUrl, fmt.Sprintf("/"))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
rl, _, err := ws.Database.Requests.ListRequestLogs(ctx, models.RequestLogFilter{}, nil, ct.Start())
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
tt.AssertEqual(t, "requestlog.count", 2, len(rl))
|
||||
|
||||
tt.AssertEqual(t, "requestlog[0].Method", "GET", rl[0].Method)
|
||||
tt.AssertEqual(t, "requestlog[0].KeyID", nil, rl[0].KeyID)
|
||||
tt.AssertEqual(t, "requestlog[0].UserID", nil, rl[0].UserID)
|
||||
tt.AssertEqual(t, "requestlog[0].Panicked", false, rl[0].Panicked)
|
||||
tt.AssertEqual(t, "requestlog[0].URI", "/", rl[0].URI)
|
||||
tt.AssertEqual(t, "requestlog[0].ResponseContentType", "text/html", rl[0].ResponseContentType)
|
||||
}
|
||||
|
||||
type R struct {
|
||||
Clients []struct {
|
||||
ClientId string `json:"client_id"`
|
||||
UserId string `json:"user_id"`
|
||||
} `json:"clients"`
|
||||
ReadKey string `json:"read_key"`
|
||||
SendKey string `json:"send_key"`
|
||||
AdminKey string `json:"admin_key"`
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
usr := tt.RequestPost[R](t, baseUrl, "/api/v2/users", gin.H{
|
||||
"agent_model": "DUMMY_PHONE",
|
||||
"agent_version": "4X",
|
||||
"client_type": "ANDROID",
|
||||
"fcm_token": "DUMMY_FCM",
|
||||
})
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// API request
|
||||
{
|
||||
|
||||
tt.RequestAuthGet[R](t, usr.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s", usr.UserId))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
rl, _, err := ws.Database.Requests.ListRequestLogs(ctx, models.RequestLogFilter{}, nil, ct.Start())
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
tt.AssertEqual(t, "requestlog.count", 4, len(rl))
|
||||
|
||||
tt.AssertEqual(t, "requestlog[0].Method", "GET", rl[0].Method)
|
||||
tt.AssertNotEqual(t, "requestlog[0].KeyID", nil, rl[0].KeyID)
|
||||
tt.AssertStrRepEqual(t, "requestlog[0].UserID", usr.UserId, rl[0].UserID)
|
||||
tt.AssertEqual(t, "requestlog[0].Panicked", false, rl[0].Panicked)
|
||||
tt.AssertStrRepEqual(t, "requestlog[0].Permissions", "A", rl[0].Permissions)
|
||||
tt.AssertEqual(t, "requestlog[0].URI", fmt.Sprintf("/api/v2/users/%s", usr.UserId), rl[0].URI)
|
||||
tt.AssertEqual(t, "requestlog[0].ResponseContentType", "application/json", rl[0].ResponseContentType)
|
||||
}
|
||||
|
||||
// Send request
|
||||
{
|
||||
tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/?user_id=%s&key=%s&title=%s", usr.UserId, usr.SendKey, url.QueryEscape("Hello World 2134")), nil)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
rl, _, err := ws.Database.Requests.ListRequestLogs(ctx, models.RequestLogFilter{}, nil, ct.Start())
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
tt.AssertEqual(t, "requestlog.count", 5, len(rl))
|
||||
|
||||
tt.AssertEqual(t, "requestlog[0].Method", "POST", rl[0].Method)
|
||||
tt.AssertEqual(t, "requestlog[0].UserID", nil, rl[0].UserID)
|
||||
tt.AssertEqual(t, "requestlog[0].ResponseContentType", "application/json", rl[0].ResponseContentType)
|
||||
}
|
||||
|
||||
// Failed request
|
||||
{
|
||||
tt.RequestAuthGetShouldFail(t, usr.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s", models.NewUserID()), 0, 0)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
rl, _, err := ws.Database.Requests.ListRequestLogs(ctx, models.RequestLogFilter{}, nil, ct.Start())
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
tt.AssertEqual(t, "requestlog.count", 6, len(rl))
|
||||
|
||||
tt.AssertEqual(t, "requestlog[0].Method", "GET", rl[0].Method)
|
||||
tt.AssertStrRepEqual(t, "requestlog[0].UserID", usr.UserId, rl[0].UserID)
|
||||
tt.AssertEqual(t, "requestlog[0].ResponseContentType", "application/json", rl[0].ResponseContentType)
|
||||
tt.AssertStrRepEqual(t, "requestlog[0].ResponseStatuscode", 401, rl[0].ResponseStatuscode)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -140,6 +140,10 @@ func AssertEqual(t *testing.T, key string, expected any, actual any) {
|
||||
|
||||
}
|
||||
|
||||
if langext.IsNil(expected) && langext.IsNil(actual) {
|
||||
return
|
||||
}
|
||||
|
||||
if expected != actual {
|
||||
t.Errorf("Value [%s] differs (%T <-> %T):\n", key, expected, actual)
|
||||
|
||||
@ -173,7 +177,7 @@ func AssertTrue(t *testing.T, key string, v bool) {
|
||||
}
|
||||
|
||||
func AssertNotEqual(t *testing.T, key string, expected any, actual any) {
|
||||
if expected == actual {
|
||||
if expected == actual || (langext.IsNil(expected) && langext.IsNil(actual)) {
|
||||
t.Errorf("Value [%s] does not differ (%T <-> %T):\n", key, expected, actual)
|
||||
|
||||
str1 := fmt.Sprintf("%v", expected)
|
||||
|
@ -395,6 +395,57 @@ func InitDefaultData(t *testing.T, ws *logic.Application) DefData {
|
||||
return DefData{User: users}
|
||||
}
|
||||
|
||||
type SingleData struct {
|
||||
UserID string
|
||||
AdminKey string
|
||||
SendKey string
|
||||
ReadKey string
|
||||
ClientID string
|
||||
}
|
||||
|
||||
func InitSingleData(t *testing.T, ws *logic.Application) SingleData {
|
||||
|
||||
// set logger to buffer, only output if error occured
|
||||
success := false
|
||||
SetBufLogger()
|
||||
defer func() {
|
||||
ClearBufLogger(!success)
|
||||
if success {
|
||||
log.Info().Msgf("Succesfully initialized default data (%d messages, %d users)", len(messageExamples), len(userExamples))
|
||||
}
|
||||
}()
|
||||
|
||||
baseUrl := "http://127.0.0.1:" + ws.Port
|
||||
|
||||
type R struct {
|
||||
Clients []struct {
|
||||
ClientId string `json:"client_id"`
|
||||
UserId string `json:"user_id"`
|
||||
} `json:"clients"`
|
||||
ReadKey string `json:"read_key"`
|
||||
SendKey string `json:"send_key"`
|
||||
AdminKey string `json:"admin_key"`
|
||||
UserId string `json:"user_id"`
|
||||
}
|
||||
|
||||
r0 := RequestPost[R](t, baseUrl, "/api/v2/users", gin.H{
|
||||
"agent_model": "DUMMY_PHONE",
|
||||
"agent_version": "4X",
|
||||
"client_type": "ANDROID",
|
||||
"fcm_token": "DUMMY_FCM",
|
||||
})
|
||||
|
||||
success = true
|
||||
|
||||
return SingleData{
|
||||
UserID: r0.UserId,
|
||||
AdminKey: r0.AdminKey,
|
||||
SendKey: r0.SendKey,
|
||||
ReadKey: r0.ReadKey,
|
||||
ClientID: r0.Clients[0].ClientId,
|
||||
}
|
||||
}
|
||||
|
||||
func doSubscribe(t *testing.T, baseUrl string, user Userdat, chanOwner Userdat, chanInternalName string) {
|
||||
|
||||
if user == chanOwner {
|
||||
|
@ -14,44 +14,48 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func RequestRaw(t *testing.T, baseURL string, urlSuffix string) {
|
||||
RequestAny[Void](t, "", "GET", baseURL, urlSuffix, nil, false)
|
||||
}
|
||||
|
||||
func RequestGet[TResult any](t *testing.T, baseURL string, urlSuffix string) TResult {
|
||||
return RequestAny[TResult](t, "", "GET", baseURL, urlSuffix, nil)
|
||||
return RequestAny[TResult](t, "", "GET", baseURL, urlSuffix, nil, true)
|
||||
}
|
||||
|
||||
func RequestAuthGet[TResult any](t *testing.T, akey string, baseURL string, urlSuffix string) TResult {
|
||||
return RequestAny[TResult](t, akey, "GET", baseURL, urlSuffix, nil)
|
||||
return RequestAny[TResult](t, akey, "GET", baseURL, urlSuffix, nil, true)
|
||||
}
|
||||
|
||||
func RequestPost[TResult any](t *testing.T, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, "", "POST", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, "", "POST", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestAuthPost[TResult any](t *testing.T, akey string, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, akey, "POST", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, akey, "POST", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestPut[TResult any](t *testing.T, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, "", "PUT", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, "", "PUT", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestAuthPUT[TResult any](t *testing.T, akey string, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, akey, "PUT", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, akey, "PUT", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestPatch[TResult any](t *testing.T, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, "", "PATCH", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, "", "PATCH", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestAuthPatch[TResult any](t *testing.T, akey string, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, akey, "PATCH", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, akey, "PATCH", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestDelete[TResult any](t *testing.T, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, "", "DELETE", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, "", "DELETE", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestAuthDelete[TResult any](t *testing.T, akey string, baseURL string, urlSuffix string, body any) TResult {
|
||||
return RequestAny[TResult](t, akey, "DELETE", baseURL, urlSuffix, body)
|
||||
return RequestAny[TResult](t, akey, "DELETE", baseURL, urlSuffix, body, true)
|
||||
}
|
||||
|
||||
func RequestGetShouldFail(t *testing.T, baseURL string, urlSuffix string, statusCode int, errcode apierr.APIError) {
|
||||
@ -86,7 +90,7 @@ func RequestAuthDeleteShouldFail(t *testing.T, akey string, baseURL string, urlS
|
||||
RequestAuthAnyShouldFail(t, akey, "DELETE", baseURL, urlSuffix, body, statusCode, errcode)
|
||||
}
|
||||
|
||||
func RequestAny[TResult any](t *testing.T, akey string, method string, baseURL string, urlSuffix string, body any) TResult {
|
||||
func RequestAny[TResult any](t *testing.T, akey string, method string, baseURL string, urlSuffix string, body any, deserialize bool) TResult {
|
||||
client := http.Client{}
|
||||
|
||||
TPrintf("[-> REQUEST] (%s) %s%s [%s] [%s]\n", method, baseURL, urlSuffix, langext.Conditional(akey == "", "NO AUTH", "AUTH"), langext.Conditional(body == nil, "NO BODY", "BODY"))
|
||||
@ -156,8 +160,10 @@ func RequestAny[TResult any](t *testing.T, akey string, method string, baseURL s
|
||||
}
|
||||
|
||||
var data TResult
|
||||
if err := json.Unmarshal(respBodyBin, &data); err != nil {
|
||||
TestFailErr(t, err)
|
||||
if deserialize {
|
||||
if err := json.Unmarshal(respBodyBin, &data); err != nil {
|
||||
TestFailErr(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
|
@ -320,3 +320,5 @@ code {
|
||||
background: #F9F9F9;
|
||||
border: .0625rem solid var(--secondary-border-color);
|
||||
}
|
||||
|
||||
code { white-space: pre; }
|
Loading…
Reference in New Issue
Block a user