Tests[SendWithTimestamp, SendInvalidTimestamp]

This commit is contained in:
Mike Schwörer 2022-11-30 22:29:12 +01:00
parent e0ecd4d9ff
commit 7eab74e65c
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
8 changed files with 209 additions and 10 deletions

View File

@ -184,7 +184,7 @@ func (h CommonHandler) Sleep(g *gin.Context) ginresp.HTTPResponse {
return ginresp.APIError(g, 400, apierr.BINDFAIL_URI_PARAM, "Failed to read uri", err) return ginresp.APIError(g, 400, apierr.BINDFAIL_URI_PARAM, "Failed to read uri", err)
} }
time.Sleep(timeext.FromSecondsFloat64(u.Seconds)) time.Sleep(timeext.FromSeconds(u.Seconds))
t1 := time.Now().Format(time.RFC3339Nano) t1 := time.Now().Format(time.RFC3339Nano)

View File

@ -152,9 +152,6 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
if Title == nil { if Title == nil {
return ginresp.SendAPIError(g, 400, apierr.MISSING_TITLE, hl.TITLE, "Missing parameter [[title]]", nil) return ginresp.SendAPIError(g, 400, apierr.MISSING_TITLE, hl.TITLE, "Missing parameter [[title]]", nil)
} }
if SendTimestamp != nil && mathext.Abs(*SendTimestamp-float64(time.Now().Unix())) > (24*time.Hour).Seconds() {
return ginresp.SendAPIError(g, 400, apierr.TIMESTAMP_OUT_OF_RANGE, hl.NONE, "The timestamp mus be within 24 hours of now()", nil)
}
if Priority != nil && (*Priority != 0 && *Priority != 1 && *Priority != 2) { if Priority != nil && (*Priority != 0 && *Priority != 1 && *Priority != 2) {
return ginresp.SendAPIError(g, 400, apierr.INVALID_PRIO, hl.PRIORITY, "Invalid priority", nil) return ginresp.SendAPIError(g, 400, apierr.INVALID_PRIO, hl.PRIORITY, "Invalid priority", nil)
} }
@ -190,6 +187,9 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
if UserMessageID != nil && len(*UserMessageID) > user.MaxUserMessageID() { if UserMessageID != nil && len(*UserMessageID) > user.MaxUserMessageID() {
return ginresp.SendAPIError(g, 400, apierr.USR_MSG_ID_TOO_LONG, hl.USER_MESSAGE_ID, fmt.Sprintf("MessageID too long (max %d characters)", user.MaxUserMessageID()), nil) return ginresp.SendAPIError(g, 400, apierr.USR_MSG_ID_TOO_LONG, hl.USER_MESSAGE_ID, fmt.Sprintf("MessageID too long (max %d characters)", user.MaxUserMessageID()), nil)
} }
if SendTimestamp != nil && mathext.Abs(*SendTimestamp-float64(time.Now().Unix())) > timeext.FromHours(user.MaxTimestampDiffHours()).Seconds() {
return ginresp.SendAPIError(g, 400, apierr.TIMESTAMP_OUT_OF_RANGE, hl.NONE, fmt.Sprintf("The timestamp mus be within %d hours of now()", user.MaxTimestampDiffHours()), nil)
}
if UserMessageID != nil { if UserMessageID != nil {
msg, err := h.database.GetMessageByUserMessageID(ctx, *UserMessageID) msg, err := h.database.GetMessageByUserMessageID(ctx, *UserMessageID)

View File

@ -8,7 +8,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16
github.com/rs/zerolog v1.28.0 github.com/rs/zerolog v1.28.0
github.com/swaggo/swag v1.8.7 github.com/swaggo/swag v1.8.7
gogs.mikescher.com/BlackForestBytes/goext v0.0.21 gogs.mikescher.com/BlackForestBytes/goext v0.0.22
) )
require ( require (

View File

@ -96,6 +96,8 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
gogs.mikescher.com/BlackForestBytes/goext v0.0.21 h1:OibsssmorZsTdFYRiQFlkXtjUYweQg9SBkWO40ONe0Y= gogs.mikescher.com/BlackForestBytes/goext v0.0.21 h1:OibsssmorZsTdFYRiQFlkXtjUYweQg9SBkWO40ONe0Y=
gogs.mikescher.com/BlackForestBytes/goext v0.0.21/go.mod h1:TMBOjo3FRFh/GiTT0z3nwLmgcFJB87oSF2VMs4XUCTQ= gogs.mikescher.com/BlackForestBytes/goext v0.0.21/go.mod h1:TMBOjo3FRFh/GiTT0z3nwLmgcFJB87oSF2VMs4XUCTQ=
gogs.mikescher.com/BlackForestBytes/goext v0.0.22 h1:D+49BDPz+2BbRwUePilIDqUsWNZIfXJKqX7yGL2b6+Q=
gogs.mikescher.com/BlackForestBytes/goext v0.0.22/go.mod h1:TMBOjo3FRFh/GiTT0z3nwLmgcFJB87oSF2VMs4XUCTQ=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=

View File

@ -102,6 +102,10 @@ func (u User) MaxUserMessageID() int {
return 64 return 64
} }
func (u User) MaxTimestampDiffHours() int {
return 24
}
type UserJSON struct { type UserJSON struct {
UserID UserID `json:"user_id"` UserID UserID `json:"user_id"`
Username *string `json:"username"` Username *string `json:"username"`

View File

@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/url" "net/url"
"testing" "testing"
"time"
) )
func TestSendSimpleMessageJSON(t *testing.T) { func TestSendSimpleMessageJSON(t *testing.T) {
@ -234,6 +235,9 @@ func TestSendContentMessage(t *testing.T) {
msgList1 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages") msgList1 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages")
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages)) tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList1.Messages[0]["title"])
tt.AssertStrRepEqual(t, "msg.content", "I am Content\nasdf", msgList1.Messages[0]["content"])
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"])) msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"]) tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"])
@ -258,6 +262,7 @@ func TestSendWithSendername(t *testing.T) {
uid := int(r0["user_id"].(float64)) uid := int(r0["user_id"].(float64))
sendtok := r0["send_key"].(string) sendtok := r0["send_key"].(string)
admintok := r0["admin_key"].(string)
msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
"user_key": sendtok, "user_key": sendtok,
@ -272,6 +277,23 @@ func TestSendWithSendername(t *testing.T) {
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", pusher.Last().Message.Content) tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", pusher.Last().Message.Content)
tt.AssertStrRepEqual(t, "msg.SenderName", "localhorst", pusher.Last().Message.SenderName) tt.AssertStrRepEqual(t, "msg.SenderName", "localhorst", pusher.Last().Message.SenderName)
tt.AssertStrRepEqual(t, "msg.scn_msg_id", msg1["scn_msg_id"], pusher.Last().Message.SCNMessageID) tt.AssertStrRepEqual(t, "msg.scn_msg_id", msg1["scn_msg_id"], pusher.Last().Message.SCNMessageID)
type mglist struct {
Messages []gin.H `json:"messages"`
}
msgList1 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages")
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msgList1.Messages[0]["title"])
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msgList1.Messages[0]["content"])
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msgList1.Messages[0]["sender_name"])
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msg1Get["title"])
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msg1Get["content"])
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msg1Get["sender_name"])
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
} }
func TestSendLongContent(t *testing.T) { func TestSendLongContent(t *testing.T) {
@ -682,6 +704,170 @@ func TestSendInvalidPriority(t *testing.T) {
tt.AssertEqual(t, "messageCount", 0, len(pusher.Data)) tt.AssertEqual(t, "messageCount", 0, len(pusher.Data))
} }
func TestSendWithTimestamp(t *testing.T) {
ws, stop := tt.StartSimpleWebserver(t)
defer stop()
pusher := ws.Pusher.(*push.TestSink)
baseUrl := "http://127.0.0.1:" + ws.Port
r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{
"agent_model": "DUMMY_PHONE",
"agent_version": "4X",
"client_type": "ANDROID",
"fcm_token": "DUMMY_FCM",
})
uid := int(r0["user_id"].(float64))
sendtok := r0["send_key"].(string)
admintok := r0["admin_key"].(string)
ts := time.Now().Unix() - int64(time.Hour.Seconds())
msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", tt.FormData{
"user_key": sendtok,
"user_id": fmt.Sprintf("%d", uid),
"title": "TTT",
"timestamp": fmt.Sprintf("%d", ts),
})
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
tt.AssertStrRepEqual(t, "msg.title", "TTT", pusher.Last().Message.Title)
tt.AssertStrRepEqual(t, "msg.TimestampClient", ts, pusher.Last().Message.TimestampClient.Unix())
tt.AssertStrRepEqual(t, "msg.Timestamp", ts, pusher.Last().Message.Timestamp().Unix())
tt.AssertNotStrRepEqual(t, "msg.ts", pusher.Last().Message.TimestampClient, pusher.Last().Message.TimestampReal)
tt.AssertStrRepEqual(t, "msg.scn_msg_id", msg1["scn_msg_id"], pusher.Last().Message.SCNMessageID)
type mglist struct {
Messages []gin.H `json:"messages"`
}
msgList1 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages")
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
tt.AssertStrRepEqual(t, "msg.title", "TTT", msgList1.Messages[0]["title"])
tt.AssertStrRepEqual(t, "msg.content", nil, msgList1.Messages[0]["sender_name"])
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
tm1, err := time.Parse(time.RFC3339Nano, msgList1.Messages[0]["timestamp"].(string))
tt.TestFailIfErr(t, err)
tt.AssertStrRepEqual(t, "msg.timestamp", ts, tm1.Unix())
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
tt.AssertStrRepEqual(t, "msg.title", "TTT", msg1Get["title"])
tt.AssertStrRepEqual(t, "msg.content", nil, msg1Get["sender_name"])
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
tmg1, err := time.Parse(time.RFC3339Nano, msg1Get["timestamp"].(string))
tt.TestFailIfErr(t, err)
tt.AssertStrRepEqual(t, "msg.timestamp", ts, tmg1.Unix())
}
func TestSendInvalidTimestamp(t *testing.T) {
ws, stop := tt.StartSimpleWebserver(t)
defer stop()
pusher := ws.Pusher.(*push.TestSink)
baseUrl := "http://127.0.0.1:" + ws.Port
r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{
"agent_model": "DUMMY_PHONE",
"agent_version": "4X",
"client_type": "ANDROID",
"fcm_token": "DUMMY_FCM",
})
uid := int(r0["user_id"].(float64))
sendtok := r0["send_key"].(string)
tt.RequestPostShouldFail(t, baseUrl, "/", tt.FormData{
"user_key": sendtok,
"user_id": fmt.Sprintf("%d", uid),
"title": "TTT",
"timestamp": "-10000",
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", tt.FormData{
"user_key": sendtok,
"user_id": fmt.Sprintf("%d", uid),
"title": "TTT",
"timestamp": "0",
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", tt.FormData{
"user_key": sendtok,
"user_id": fmt.Sprintf("%d", uid),
"title": "TTT",
"timestamp": fmt.Sprintf("%d", time.Now().Unix()-int64(25*time.Hour.Seconds())),
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", tt.FormData{
"user_key": sendtok,
"user_id": fmt.Sprintf("%d", uid),
"title": "TTT",
"timestamp": fmt.Sprintf("%d", time.Now().Unix()+int64(25*time.Hour.Seconds())),
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{
"user_key": sendtok,
"user_id": uid,
"title": "TTT",
"timestamp": -10000,
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{
"user_key": sendtok,
"user_id": uid,
"title": "TTT",
"timestamp": 0,
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{
"user_key": sendtok,
"user_id": uid,
"title": "TTT",
"timestamp": time.Now().Unix() - int64(25*time.Hour.Seconds()),
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{
"user_key": sendtok,
"user_id": uid,
"title": "TTT",
"timestamp": time.Now().Unix() + int64(25*time.Hour.Seconds()),
}, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, fmt.Sprintf("/?user_key=%s&user_id=%d&title=%s&timestamp=%d",
sendtok,
uid,
"TTT",
-10000,
), nil, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, fmt.Sprintf("/?user_key=%s&user_id=%d&title=%s&timestamp=%d",
sendtok,
uid,
"TTT",
0,
), nil, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, fmt.Sprintf("/?user_key=%s&user_id=%d&title=%s&timestamp=%d",
sendtok,
uid,
"TTT",
time.Now().Unix()-int64(25*time.Hour.Seconds()),
), nil, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.RequestPostShouldFail(t, baseUrl, fmt.Sprintf("/?user_key=%s&user_id=%d&title=%s&timestamp=%d",
sendtok,
uid,
"TTT",
time.Now().Unix()+int64(25*time.Hour.Seconds()),
), nil, 400, apierr.TIMESTAMP_OUT_OF_RANGE)
tt.AssertEqual(t, "messageCount", 0, len(pusher.Data))
}
//TODO compat route //TODO compat route
//TODO post to channel //TODO post to channel
@ -696,10 +882,6 @@ func TestSendInvalidPriority(t *testing.T) {
//TODO chan_name normalization //TODO chan_name normalization
//TODO custom_timestamp
//TODO invalid time
//TODO check message_counter + last_sent in channel //TODO check message_counter + last_sent in channel
//TODO check message_counter + last_sent in user //TODO check message_counter + last_sent in user

View File

@ -133,19 +133,28 @@ func AssertNotStrRepEqual(t *testing.T, key string, expected any, actual any) {
func TestFail(t *testing.T, msg string) { func TestFail(t *testing.T, msg string) {
t.Error(msg) t.Error(msg)
t.Error(string(debug.Stack()))
t.FailNow() t.FailNow()
} }
func TestFailFmt(t *testing.T, format string, args ...any) { func TestFailFmt(t *testing.T, format string, args ...any) {
t.Errorf(format, args...) t.Errorf(format, args...)
t.Error(string(debug.Stack()))
t.FailNow() t.FailNow()
} }
func TestFailErr(t *testing.T, e error) { func TestFailErr(t *testing.T, e error) {
t.Error(fmt.Sprintf("Failed with error:\n%s\n\nError:\n%+v\n\nTrace:\n%s", e.Error(), e, string(debug.Stack()))) t.Error(fmt.Sprintf("Failed with error:\n%s\n\nError:\n%+v\n\nTrace:\n%s", e.Error(), e, string(debug.Stack())))
t.Error(string(debug.Stack()))
t.FailNow() t.FailNow()
} }
func TestFailIfErr(t *testing.T, e error) {
if e != nil {
TestFailErr(t, e)
}
}
func unpointer(v any) any { func unpointer(v any) any {
if v == nil { if v == nil {
return v return v

View File

@ -224,7 +224,9 @@ func RequestAuthAnyShouldFail(t *testing.T, akey string, method string, baseURL
fmt.Println("") fmt.Println("")
fmt.Printf("---------------- RESPONSE (%d) ----------------\n", resp.StatusCode) fmt.Printf("---------------- RESPONSE (%d) ----------------\n", resp.StatusCode)
fmt.Println(langext.TryPrettyPrintJson(string(respBodyBin))) fmt.Println(langext.TryPrettyPrintJson(string(respBodyBin)))
//TryPrintTraceObj("---------------- -------- ----------------", respBodyBin, "") if resp.StatusCode != statusCode {
TryPrintTraceObj("---------------- -------- ----------------", respBodyBin, "")
}
fmt.Println("---------------- -------- ----------------") fmt.Println("---------------- -------- ----------------")
fmt.Println("") fmt.Println("")