diff --git a/comms/Makefile b/comms/Makefile index 3cc372e2911..bd1a88e8b72 100644 --- a/comms/Makefile +++ b/comms/Makefile @@ -39,7 +39,7 @@ fmt:: test:: docker compose up -d comdb - go test ./... -count=1 -p=1 + go test ./... diff --git a/comms/internal/rpcz/chat_block_test.go b/comms/internal/rpcz/chat_block_test.go index 331fd9ada21..727d277aa88 100644 --- a/comms/internal/rpcz/chat_block_test.go +++ b/comms/internal/rpcz/chat_block_test.go @@ -2,6 +2,8 @@ package rpcz import ( "fmt" + "math/rand" + "strconv" "testing" "time" @@ -22,9 +24,11 @@ func TestChatBlocking(t *testing.T) { tx := db.Conn.MustBegin() - // TODO test queries + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() - assertBlocked := func(blockerUserId int, blockeeUserId int, timestamp time.Time, expected int) { + assertBlocked := func(blockerUserId int32, blockeeUserId int32, timestamp time.Time, expected int) { row := tx.QueryRow("select count(*) from chat_blocked_users where blocker_user_id = $1 and blockee_user_id = $2 and created_at = $3", blockerUserId, blockeeUserId, timestamp) var count int err = row.Scan(&count) @@ -32,56 +36,56 @@ func TestChatBlocking(t *testing.T) { assert.Equal(t, expected, count) } - // validate 91 can block 92 + // validate user1Id can block user2Id { - hashUserId, err := misc.EncodeHashId(92) + encodedUserId, err := misc.EncodeHashId(int(user2Id)) assert.NoError(t, err) exampleRpc := schema.RawRPC{ - Params: []byte(fmt.Sprintf(`{"user_id": "%s"}`, hashUserId)), + Params: []byte(fmt.Sprintf(`{"user_id": "%s"}`, encodedUserId)), } chatBlock := string(schema.RPCMethodChatBlock) - err = Validators[chatBlock](tx, 91, exampleRpc) + err = Validators[chatBlock](tx, user1Id, exampleRpc) assert.NoError(t, err) } - // user 91 blocks 92 + // user1Id blocks user2Id messageTs := time.Now() - err = chatBlock(tx, 91, 92, messageTs) + err = chatBlock(tx, user1Id, user2Id, messageTs) assert.NoError(t, err) - assertBlocked(91, 92, messageTs, 1) + assertBlocked(user1Id, user2Id, messageTs, 1) // assert no update if duplicate block requests duplicateMessageTs := time.Now() - err = chatBlock(tx, 91, 92, duplicateMessageTs) + err = chatBlock(tx, user1Id, user2Id, duplicateMessageTs) assert.NoError(t, err) - assertBlocked(91, 92, messageTs, 1) - assertBlocked(91, 92, duplicateMessageTs, 0) + assertBlocked(user1Id, user2Id, messageTs, 1) + assertBlocked(user1Id, user2Id, duplicateMessageTs, 0) - // validate 91 and 92 cannot create a chat with each other + // validate user1Id and user2Id cannot create a chat with each other { - chatId := "chat1" - user91HashId, err := misc.EncodeHashId(91) + chatId := strconv.Itoa(seededRand.Int()) + user1IdEncoded, err := misc.EncodeHashId(int(user1Id)) assert.NoError(t, err) - user92HashId, err := misc.EncodeHashId(92) + user2IdEncoded, err := misc.EncodeHashId(int(user2Id)) assert.NoError(t, err) exampleRpc := schema.RawRPC{ - Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "1"}, {"user_id": "%s", "invite_code": "2"}]}`, chatId, user91HashId, user92HashId)), + Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "1"}, {"user_id": "%s", "invite_code": "2"}]}`, chatId, user1IdEncoded, user2IdEncoded)), } chatCreate := string(schema.RPCMethodChatCreate) - err = Validators[chatCreate](tx, 91, exampleRpc) + err = Validators[chatCreate](tx, user1Id, exampleRpc) assert.ErrorContains(t, err, "Cannot chat with a user you have blocked or user who has blocked you") } - // validate 91 and 92 cannot message each other + // validate user1Id and user2Id cannot message each other { // Assume chat was already created before blocking - chatId := "chat1" - SetupChatWithMembers(t, tx, chatId, 91, 92) + chatId := strconv.Itoa(seededRand.Int()) + SetupChatWithMembers(t, tx, chatId, user1Id, user2Id) exampleRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message_id": "1", "message": "test"}`, chatId)), @@ -89,14 +93,14 @@ func TestChatBlocking(t *testing.T) { chatMessage := string(schema.RPCMethodChatMessage) - err = Validators[chatMessage](tx, 91, exampleRpc) + err = Validators[chatMessage](tx, user1Id, exampleRpc) assert.ErrorContains(t, err, "Cannot chat with a user you have blocked or user who has blocked you") } - // user 91 unblocks 92 - err = chatUnblock(tx, 91, 92) + // user1Id unblocks user2Id + err = chatUnblock(tx, user1Id, user2Id) assert.NoError(t, err) - assertBlocked(91, 92, messageTs, 0) + assertBlocked(user1Id, user2Id, messageTs, 0) tx.Rollback() } diff --git a/comms/internal/rpcz/chat_delete_test.go b/comms/internal/rpcz/chat_delete_test.go index bb8d70bed68..834bbb96231 100644 --- a/comms/internal/rpcz/chat_delete_test.go +++ b/comms/internal/rpcz/chat_delete_test.go @@ -3,6 +3,8 @@ package rpcz import ( "database/sql" "fmt" + "math/rand" + "strconv" "testing" "time" @@ -20,10 +22,15 @@ func TestChatDeletion(t *testing.T) { tx := db.Conn.MustBegin() - chatId := "chat1" - SetupChatWithMembers(t, tx, chatId, 91, 92) + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() + user3Id := seededRand.Int31() + chatId := strconv.Itoa(seededRand.Int()) - assertDeleted := func(chatId string, userId int, expectDeleted bool) { + SetupChatWithMembers(t, tx, chatId, user1Id, user2Id) + + assertDeleted := func(chatId string, userId int32, expectDeleted bool) { row := tx.QueryRow("select cleared_history_at from chat_member where chat_id = $1 and user_id = $2", chatId, userId) var clearedHistoryAt sql.NullTime err = row.Scan(&clearedHistoryAt) @@ -35,7 +42,7 @@ func TestChatDeletion(t *testing.T) { } } - // validate 91 and 92 can delete their chats + // validate user1Id and user2Id can delete their chats { exampleRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s"}`, chatId)), @@ -43,21 +50,21 @@ func TestChatDeletion(t *testing.T) { chatDelete := string(schema.RPCMethodChatDelete) - err = Validators[chatDelete](tx, 91, exampleRpc) + err = Validators[chatDelete](tx, user1Id, exampleRpc) assert.NoError(t, err) - err = Validators[chatDelete](tx, 93, exampleRpc) + err = Validators[chatDelete](tx, user3Id, exampleRpc) assert.ErrorIs(t, err, sql.ErrNoRows) } - // 91 deletes the chat + // user1Id deletes the chat deleteTs := time.Now() - err = chatDelete(tx, 91, chatId, deleteTs) + err = chatDelete(tx, user1Id, chatId, deleteTs) assert.NoError(t, err) - assertDeleted(chatId, 91, true) + assertDeleted(chatId, user1Id, true) - // chat is not deleted for 92 - assertDeleted(chatId, 92, false) + // chat is not deleted for user2Id + assertDeleted(chatId, user2Id, false) tx.Rollback() } diff --git a/comms/internal/rpcz/chat_permissions_test.go b/comms/internal/rpcz/chat_permissions_test.go index e6763c6ab91..75461e8a6d1 100644 --- a/comms/internal/rpcz/chat_permissions_test.go +++ b/comms/internal/rpcz/chat_permissions_test.go @@ -2,7 +2,9 @@ package rpcz import ( "fmt" + "math/rand" "testing" + "time" "comms.audius.co/db" "comms.audius.co/schema" @@ -18,6 +20,9 @@ func TestChatPermissions(t *testing.T) { tx := db.Conn.MustBegin() + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + user1Id := seededRand.Int31() + assertPermissions := func(userId int32, permits schema.ChatPermission, expected int) { row := tx.QueryRow("select count(*) from chat_permissions where user_id = $1 and permits = $2", userId, permits) var count int @@ -26,7 +31,7 @@ func TestChatPermissions(t *testing.T) { assert.Equal(t, expected, count) } - // validate 91 can set permissions + // validate user1Id can set permissions { exampleRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"permit": "all"}`)), @@ -34,17 +39,17 @@ func TestChatPermissions(t *testing.T) { chatPermit := string(schema.RPCMethodChatPermit) - err = Validators[chatPermit](tx, 91, exampleRpc) + err = Validators[chatPermit](tx, user1Id, exampleRpc) assert.NoError(t, err) } - // 91 sets chat permissions to followees only - userId := int32(91) + // user1Id sets chat permissions to followees only + userId := int32(user1Id) err = chatSetPermissions(tx, userId, schema.Followees) assert.NoError(t, err) assertPermissions(userId, schema.Followees, 1) - // 91 changes chat permissions to none + // user1Id changes chat permissions to none err = chatSetPermissions(tx, userId, schema.None) assert.NoError(t, err) assertPermissions(userId, schema.Followees, 0) diff --git a/comms/internal/rpcz/chat_test.go b/comms/internal/rpcz/chat_test.go index 54ecc2e2c98..fa36cee41ce 100644 --- a/comms/internal/rpcz/chat_test.go +++ b/comms/internal/rpcz/chat_test.go @@ -3,6 +3,8 @@ package rpcz import ( "database/sql" "fmt" + "math/rand" + "strconv" "testing" "time" @@ -18,15 +20,19 @@ import ( func TestChat(t *testing.T) { var err error - chatId := "chat1" - // reset tables under test _, err = db.Conn.Exec("truncate table chat cascade") assert.NoError(t, err) tx := db.Conn.MustBegin() - SetupChatWithMembers(t, tx, chatId, 91, 92) + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + chatId := strconv.Itoa(seededRand.Int()) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() + user3Id := seededRand.Int31() + + SetupChatWithMembers(t, tx, chatId, user1Id, user2Id) // Connect to NATS and create JetStream Context opts := server.Options{ @@ -43,7 +49,7 @@ func TestChat(t *testing.T) { assert.NoError(t, err) jetstream.SetJetstreamContext(js) - // validate 91 and 92 can both send messages in this chat + // validate user1Id and user2Id can both send messages in this chat { exampleRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "test123"}`, chatId)), @@ -51,28 +57,28 @@ func TestChat(t *testing.T) { chatMessage := string(schema.RPCMethodChatMessage) - err = Validators[chatMessage](tx, 91, exampleRpc) + err = Validators[chatMessage](tx, user1Id, exampleRpc) assert.NoError(t, err) - err = Validators[chatMessage](tx, 93, exampleRpc) + err = Validators[chatMessage](tx, user3Id, exampleRpc) assert.ErrorIs(t, err, sql.ErrNoRows) } - // 91 sends 92 a message + // user1Id sends user2Id a message messageTs := time.Now() - messageId := "1" - err = chatSendMessage(tx, 91, chatId, messageId, messageTs, "hello 92") + messageId := strconv.Itoa(seededRand.Int()) + err = chatSendMessage(tx, user1Id, chatId, messageId, messageTs, "hello user2Id") assert.NoError(t, err) // assertUnreadCount helper fun in a closure - assertUnreadCount := func(chatId string, userId int, expected int) { + assertUnreadCount := func(chatId string, userId int32, expected int) { unreadCount := 0 err := tx.Get(&unreadCount, "select unread_count from chat_member where chat_id = $1 and user_id = $2", chatId, userId) assert.NoError(t, err) assert.Equal(t, expected, unreadCount) } - assertReaction := func(userId int, messageId string, expected *string) { + assertReaction := func(userId int32, messageId string, expected *string) { var reaction string err := tx.Get(&reaction, "select reaction from chat_message_reactions where user_id = $1 and message_id = $2", userId, messageId) if expected != nil { @@ -84,28 +90,28 @@ func TestChat(t *testing.T) { } // assert sender has no unread messages - assertUnreadCount(chatId, 91, 0) + assertUnreadCount(chatId, user1Id, 0) - // assert 92 has one unread message - assertUnreadCount(chatId, 92, 1) + // assert user2Id has one unread message + assertUnreadCount(chatId, user2Id, 1) - // 92 reads message - chatReadMessages(tx, 92, chatId, time.Now()) + // user2Id reads message + chatReadMessages(tx, user2Id, chatId, time.Now()) - // assert 92 has zero unread messages - assertUnreadCount(chatId, 92, 0) + // assert user2Id has zero unread messages + assertUnreadCount(chatId, user2Id, 0) - // 92 sends a reply to 91 + // user2Id sends a reply to user1Id replyTs := time.Now() replyMessageId := "2" - err = chatSendMessage(tx, 92, chatId, replyMessageId, replyTs, "oh hey there 91 thanks for your message") + err = chatSendMessage(tx, user2Id, chatId, replyMessageId, replyTs, "oh hey there user1 thanks for your message") assert.NoError(t, err) // the tables have turned! - assertUnreadCount(chatId, 92, 0) - assertUnreadCount(chatId, 91, 1) + assertUnreadCount(chatId, user2Id, 0) + assertUnreadCount(chatId, user1Id, 1) - // validate 91 and 92 can both send reactions in this chat + // validate user1Id and user2Id can both send reactions in this chat { exampleRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message_id": "%s", "reaction": "heart"}`, chatId, replyMessageId)), @@ -113,29 +119,29 @@ func TestChat(t *testing.T) { chatReact := string(schema.RPCMethodChatReact) - err = Validators[chatReact](tx, 91, exampleRpc) + err = Validators[chatReact](tx, user1Id, exampleRpc) assert.NoError(t, err) - err = Validators[chatReact](tx, 93, exampleRpc) + err = Validators[chatReact](tx, user3Id, exampleRpc) assert.ErrorIs(t, err, sql.ErrNoRows) } - // 91 reacts to 92's message + // user1Id reacts to user2Id's message reactTs := time.Now() reaction := "fire" - err = chatReactMessage(tx, 91, replyMessageId, &reaction, reactTs) - assertReaction(91, replyMessageId, &reaction) + err = chatReactMessage(tx, user1Id, replyMessageId, &reaction, reactTs) + assertReaction(user1Id, replyMessageId, &reaction) - // 91 changes reaction to 92's message + // user1Id changes reaction to user2Id's message changedReactTs := time.Now() newReaction := "heart" - err = chatReactMessage(tx, 91, replyMessageId, &newReaction, changedReactTs) - assertReaction(91, replyMessageId, &newReaction) + err = chatReactMessage(tx, user1Id, replyMessageId, &newReaction, changedReactTs) + assertReaction(user1Id, replyMessageId, &newReaction) - // 91 removes reaction to 92's message + // user1Id removes reaction to user2Id's message removedReactTs := time.Now() - err = chatReactMessage(tx, 91, replyMessageId, nil, removedReactTs) - assertReaction(91, replyMessageId, nil) + err = chatReactMessage(tx, user1Id, replyMessageId, nil, removedReactTs) + assertReaction(user1Id, replyMessageId, nil) tx.Rollback() } diff --git a/comms/internal/rpcz/rate_limit_test.go b/comms/internal/rpcz/rate_limit_test.go index 1b09742799a..22de9f0779f 100644 --- a/comms/internal/rpcz/rate_limit_test.go +++ b/comms/internal/rpcz/rate_limit_test.go @@ -2,6 +2,7 @@ package rpcz import ( "fmt" + "math/rand" "strconv" "testing" "time" @@ -60,120 +61,126 @@ func TestRateLimit(t *testing.T) { tx := db.Conn.MustBegin() + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) chatMessage := string(schema.RPCMethodChatMessage) chatCreate := string(schema.RPCMethodChatCreate) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() + user3Id := seededRand.Int31() + user4Id := seededRand.Int31() + user5Id := seededRand.Int31() - user91Encoded, err := misc.EncodeHashId(91) + user1IdEncoded, err := misc.EncodeHashId(int(user1Id)) assert.NoError(t, err) - user93Encoded, err := misc.EncodeHashId(93) + user3IdEncoded, err := misc.EncodeHashId(int(user3Id)) assert.NoError(t, err) - user94Encoded, err := misc.EncodeHashId(94) + user4IdEncoded, err := misc.EncodeHashId(int(user4Id)) assert.NoError(t, err) - user95Encoded, err := misc.EncodeHashId(95) + user5IdEncoded, err := misc.EncodeHashId(int(user5Id)) assert.NoError(t, err) - // 91 created a new chat with 92 48 hours ago - chatId1 := "chat1" + // user1Id created a new chat with user2Id 48 hours ago + chatId1 := strconv.Itoa(seededRand.Int()) chatTs := time.Now().UTC().Add(-time.Hour * time.Duration(48)) _, err = tx.Exec("insert into chat (chat_id, created_at, last_message_at) values ($1, $2, $2)", chatId1, chatTs) assert.NoError(t, err) - _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3)", chatId1, 91, 92) + _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3)", chatId1, user1Id, user2Id) assert.NoError(t, err) - // 91 messaged 92 48 hours ago - err = chatSendMessage(tx, 91, chatId1, "1", chatTs, "Hello") + // user1Id messaged user2Id 48 hours ago + err = chatSendMessage(tx, user1Id, chatId1, "1", chatTs, "Hello") assert.NoError(t, err) - // 91 messages 92 twice now + // user1Id messages user2Id twice now message := "Hello today 1" messageRpc := schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId1, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.NoError(t, err) - err = chatSendMessage(tx, 91, chatId1, "2", time.Now().UTC(), message) + err = chatSendMessage(tx, user1Id, chatId1, "2", time.Now().UTC(), message) assert.NoError(t, err) message = "Hello today 2" messageRpc = schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId1, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.NoError(t, err) - err = chatSendMessage(tx, 91, chatId1, "3", time.Now().UTC(), message) + err = chatSendMessage(tx, user1Id, chatId1, "3", time.Now().UTC(), message) assert.NoError(t, err) - // 91 messages 92 a 3rd time + // user1Id messages user2Id a 3rd time // Blocked by rate limiter (hit max # messages per recipient in the past 24 hours) message = "Hello again again." messageRpc = schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId1, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.ErrorContains(t, err, "User has exceeded the maximum number of new messages") - // 91 creates a new chat with 93 (1 chat created in 24h) - chatId2 := "chat2" + // user1Id creates a new chat with user3Id (1 chat created in 24h) + chatId2 := strconv.Itoa(seededRand.Int()) createRpc := schema.RawRPC{ - Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId2, user91Encoded, chatId2, user93Encoded, chatId2)), + Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId2, user1IdEncoded, chatId2, user3IdEncoded, chatId2)), } - err = Validators[chatCreate](tx, 91, createRpc) + err = Validators[chatCreate](tx, user1Id, createRpc) assert.NoError(t, err) - SetupChatWithMembers(t, tx, chatId2, 91, 93) + SetupChatWithMembers(t, tx, chatId2, user1Id, user3Id) - // 91 messages 93 - // Still blocked by rate limiter (hit max # messages with 92 in the past 24h) - message = "Hi 93" + // user1Id messages user3Id + // Still blocked by rate limiter (hit max # messages with user2Id in the past 24h) + message = "Hi user3Id" messageRpc = schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId2, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.ErrorContains(t, err, "User has exceeded the maximum number of new messages") // Remove message 3 from db so can test other rate limits _, err = tx.Exec("delete from chat_message where message_id = '3'") assert.NoError(t, err) - // 91 should be able to message 93 now - err = Validators[chatMessage](tx, 91, messageRpc) + // user1Id should be able to message user3Id now + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.NoError(t, err) - err = chatSendMessage(tx, 91, chatId2, "3", time.Now().UTC(), message) + err = chatSendMessage(tx, user1Id, chatId2, "3", time.Now().UTC(), message) assert.NoError(t, err) - // 91 creates a new chat with 94 (2 chats created in 24h) - chatId3 := "chat3" + // user1Id creates a new chat with user4Id (2 chats created in 24h) + chatId3 := strconv.Itoa(seededRand.Int()) createRpc = schema.RawRPC{ - Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId3, user91Encoded, chatId3, user94Encoded, chatId3)), + Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId3, user1IdEncoded, chatId3, user4IdEncoded, chatId3)), } - err = Validators[chatCreate](tx, 91, createRpc) + err = Validators[chatCreate](tx, user1Id, createRpc) assert.NoError(t, err) - SetupChatWithMembers(t, tx, chatId3, 91, 94) + SetupChatWithMembers(t, tx, chatId3, user1Id, user4Id) - // 91 messages 94 - message = "Hi 94 again" + // user1Id messages user4Id + message = "Hi user4Id again" messageRpc = schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId3, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.NoError(t, err) - err = chatSendMessage(tx, 91, chatId3, "4", time.Now().UTC(), message) + err = chatSendMessage(tx, user1Id, chatId3, "4", time.Now().UTC(), message) assert.NoError(t, err) - // 91 messages 94 again (4th message to anyone in 24h) + // user1Id messages user4Id again (4th message to anyone in 24h) // Blocked by rate limiter (hit max # messages in the past 24 hours) - message = "Hi 94 again" + message = "Hi user4Id again" messageRpc = schema.RawRPC{ Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "message": "%s"}`, chatId3, message)), } - err = Validators[chatMessage](tx, 91, messageRpc) + err = Validators[chatMessage](tx, user1Id, messageRpc) assert.ErrorContains(t, err, "User has exceeded the maximum number of new messages") - // 91 creates a new chat with 95 (3 chats created in 24h) + // user1Id creates a new chat with user5Id (3 chats created in 24h) // Blocked by rate limiter (hit max # new chats) - chatId4 := "chat4" + chatId4 := strconv.Itoa(seededRand.Int()) createRpc = schema.RawRPC{ - Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId4, user91Encoded, chatId2, user95Encoded, chatId4)), + Params: []byte(fmt.Sprintf(`{"chat_id": "%s", "invites": [{"user_id": "%s", "invite_code": "%s"}, {"user_id": "%s", "invite_code": "%s"}]}`, chatId4, user1IdEncoded, chatId2, user5IdEncoded, chatId4)), } - err = Validators[chatCreate](tx, 91, createRpc) + err = Validators[chatCreate](tx, user1Id, createRpc) assert.ErrorContains(t, err, "An invited user has exceeded the maximum number of new chats") tx.Rollback() diff --git a/comms/internal/rpcz/test_utils.go b/comms/internal/rpcz/test_utils.go index 3eff010eff2..274d8158217 100644 --- a/comms/internal/rpcz/test_utils.go +++ b/comms/internal/rpcz/test_utils.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" ) -func SetupChatWithMembers(t *testing.T, tx *sqlx.Tx, chatId string, user1 int, user2 int) { +func SetupChatWithMembers(t *testing.T, tx *sqlx.Tx, chatId string, user1 int32, user2 int32) { var err error // create chat diff --git a/comms/internal/rpcz/validator.go b/comms/internal/rpcz/validator.go index 303a2ed69db..ecd4307b940 100644 --- a/comms/internal/rpcz/validator.go +++ b/comms/internal/rpcz/validator.go @@ -288,12 +288,12 @@ func validateNotBlocked(q db.Queryable, user1 int32, user2 int32) error { func getRateLimit(kv nats.KeyValue, rule string, fallback int) int { got, err := kv.Get(rule) if err != nil { - config.Logger.Warn("unable to retrive rate limit KV rule, using default value", "error", err, "rule", rule) + config.Logger.Debug("unable to retrive rate limit KV rule, using default value", "error", err, "rule", rule) return fallback } limit, err := strconv.Atoi(string(got.Value())) if err != nil { - config.Logger.Warn("unable to convert rate limit from KV to int, using default value", "error", err, "rule", rule) + config.Logger.Debug("unable to convert rate limit from KV to int, using default value", "error", err, "rule", rule) return fallback } return limit @@ -317,7 +317,7 @@ func validateNewChatRateLimit(q db.Queryable, users []int32) error { timeframe = getRateLimit(kv, config.RateLimitTimeframeHours, timeframe) maxNumChats = getRateLimit(kv, config.RateLimitMaxNumNewChats, maxNumChats) } else { - config.Logger.Warn("unable to retrive rate limit KV, using default values", "error", err) + config.Logger.Debug("unable to retrive rate limit KV, using default values", "error", err) } cursor := calculateRateLimitCursor(timeframe) @@ -352,7 +352,7 @@ func validateNewMessageRateLimit(q db.Queryable, userId int32, chatId string) er maxNumMessages = getRateLimit(kv, config.RateLimitMaxNumMessages, maxNumMessages) maxNumMessagesPerRecipient = getRateLimit(kv, config.RateLimitMaxNumMessagesPerRecipient, maxNumMessagesPerRecipient) } else { - config.Logger.Warn("unable to retrive rate limit KV, using default values", "error", err) + config.Logger.Debug("unable to retrive rate limit KV, using default values", "error", err) } // Cursor for rate limit timeframe diff --git a/comms/server/server.go b/comms/server/server.go index e38b68a0c31..343a1cc728a 100644 --- a/comms/server/server.go +++ b/comms/server/server.go @@ -292,7 +292,10 @@ func createServer() *echo.Echo { } // call validator - rpcz.Validate(userId, rawRpc) + err = rpcz.Validate(userId, rawRpc) + if err != nil { + return c.JSON(400, "bad request: "+err.Error()) + } subject := "audius.dms.demo" jsc := jetstream.GetJetstreamContext() diff --git a/comms/server/server_test.go b/comms/server/server_test.go index e7a99199a87..e3a4e9ecfa6 100644 --- a/comms/server/server_test.go +++ b/comms/server/server_test.go @@ -6,8 +6,10 @@ import ( "encoding/json" "fmt" "log" + "math/rand" "net/http" "net/http/httptest" + "strconv" "testing" "time" @@ -20,20 +22,6 @@ import ( "github.com/stretchr/testify/assert" ) -// func TestServer(t *testing.T) { -// e := createServer() -// req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(userJSON)) -// req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) -// rec := httptest.NewRecorder() -// c := e.NewContext(req, rec) - -// // Assertions -// if assert.NoError(t, h.createUser(c)) { -// assert.Equal(t, http.StatusCreated, rec.Code) -// assert.Equal(t, userJSON, rec.Body.String()) -// } -// } - func TestSig(t *testing.T) { privateKey, err := crypto.GenerateKey() assert.NoError(t, err) @@ -50,8 +38,6 @@ func TestSig(t *testing.T) { log.Fatal(err) } - // fmt.Println(hexutil.Encode(signature)) - // recover sigPublicKey, err := crypto.SigToPub(hash.Bytes(), signature) if err != nil { @@ -88,20 +74,26 @@ func TestGetChats(t *testing.T) { assert.NoError(t, err) tx := db.Conn.MustBegin() + + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() + user3Id := seededRand.Int31() + // Create 3 users - _, err = tx.Exec("insert into users (user_id, wallet, is_current) values ($1, lower($2), true), ($3, lower($4), true), ($5, lower($6), true)", 1, wallet1, 2, wallet2, 3, wallet3) + _, err = tx.Exec("insert into users (user_id, wallet, is_current) values ($1, lower($2), true), ($3, lower($4), true), ($5, lower($6), true)", user1Id, wallet1, user2Id, wallet2, user3Id, wallet3) assert.NoError(t, err) // Create 2 chats - chatId1 := "chat1" - chatId2 := "chat2" + chatId1 := strconv.Itoa(seededRand.Int()) + chatId2 := strconv.Itoa(seededRand.Int()) chat1CreatedAt := time.Now().UTC().Add(-time.Minute * time.Duration(60)) chat2CreatedAt := time.Now().UTC().Add(-time.Minute * time.Duration(30)) _, err = tx.Exec("insert into chat (chat_id, created_at, last_message_at) values ($1, $2, $2), ($3, $4, $4)", chatId1, chat1CreatedAt, chatId2, chat2CreatedAt) assert.NoError(t, err) // Insert members into chats (1 and 2, 1 and 3) - _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3), ($4, $2, $4, $2), ($4, $2, $4, $5)", chatId1, 1, 2, chatId2, 3) + _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3), ($4, $2, $4, $2), ($4, $2, $4, $5)", chatId1, user1Id, user2Id, chatId2, user3Id) assert.NoError(t, err) err = tx.Commit() assert.NoError(t, err) @@ -110,11 +102,11 @@ func TestGetChats(t *testing.T) { expectedHealth := schema.Health{ IsHealthy: true, } - encodedUser1, err := misc.EncodeHashId(1) + encodedUser1, err := misc.EncodeHashId(int(user1Id)) assert.NoError(t, err) - encodedUser2, err := misc.EncodeHashId(2) + encodedUser2, err := misc.EncodeHashId(int(user2Id)) assert.NoError(t, err) - encodedUser3, err := misc.EncodeHashId(3) + encodedUser3, err := misc.EncodeHashId(int(user3Id)) assert.NoError(t, err) expectedMember1 := schema.ChatMember{ UserID: encodedUser1, @@ -246,18 +238,23 @@ func TestGetMessages(t *testing.T) { assert.NoError(t, err) tx := db.Conn.MustBegin() + + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + user1Id := seededRand.Int31() + user2Id := seededRand.Int31() + // Create 2 users - _, err = tx.Exec("insert into users (user_id, wallet, is_current) values ($1, lower($2), true), ($3, lower($4), true)", 1, wallet1, 2, wallet2) + _, err = tx.Exec("insert into users (user_id, wallet, is_current) values ($1, lower($2), true), ($3, lower($4), true)", user1Id, wallet1, user2Id, wallet2) assert.NoError(t, err) // Create a chat - chatId := "chat1" + chatId := strconv.Itoa(seededRand.Int()) chatCreatedAt := time.Now().UTC().Add(-time.Hour * time.Duration(2)) _, err = tx.Exec("insert into chat (chat_id, created_at, last_message_at) values ($1, $2, $2)", chatId, chatCreatedAt) assert.NoError(t, err) // Insert members 1 and 2 into chat - _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3)", chatId, 1, 2) + _, err = tx.Exec("insert into chat_member (chat_id, invited_by_user_id, invite_code, user_id) values ($1, $2, $1, $2), ($1, $2, $1, $3)", chatId, user1Id, user2Id) assert.NoError(t, err) // Insert chat messages @@ -267,7 +264,7 @@ func TestGetMessages(t *testing.T) { messageId2 := "message2" message2CreatedAt := time.Now().UTC().Add(-time.Hour * time.Duration(1)) message2 := "ack from user 2" - _, err = tx.Exec("insert into chat_message (message_id, chat_id, user_id, created_at, ciphertext) values ($1, $2, $3, $4, $5), ($6, $2, $7, $8, $9)", messageId1, chatId, 1, message1CreatedAt, message1, messageId2, 2, message2CreatedAt, message2) + _, err = tx.Exec("insert into chat_message (message_id, chat_id, user_id, created_at, ciphertext) values ($1, $2, $3, $4, $5), ($6, $2, $7, $8, $9)", messageId1, chatId, user1Id, message1CreatedAt, message1, messageId2, user2Id, message2CreatedAt, message2) assert.NoError(t, err) // Insert 2 message reactions to message 1 @@ -275,7 +272,7 @@ func TestGetMessages(t *testing.T) { reaction1CreatedAt := time.Now().UTC().Add(-time.Minute * time.Duration(30)) reaction2 := "fire" reaction2CreatedAt := time.Now().UTC().Add(-time.Minute * time.Duration(15)) - _, err = tx.Exec("insert into chat_message_reactions (user_id, message_id, reaction, created_at) values ($1, $2, $3, $4), ($5, $2, $6, $7)", 1, messageId1, reaction1, reaction1CreatedAt, 2, reaction2, reaction2CreatedAt) + _, err = tx.Exec("insert into chat_message_reactions (user_id, message_id, reaction, created_at) values ($1, $2, $3, $4), ($5, $2, $6, $7)", user1Id, messageId1, reaction1, reaction1CreatedAt, user2Id, reaction2, reaction2CreatedAt) assert.NoError(t, err) err = tx.Commit() @@ -302,9 +299,9 @@ func TestGetMessages(t *testing.T) { defer res.Body.Close() // Assertions - encodedUser1, err := misc.EncodeHashId(1) + encodedUser1, err := misc.EncodeHashId(int(user1Id)) assert.NoError(t, err) - encodedUser2, err := misc.EncodeHashId(2) + encodedUser2, err := misc.EncodeHashId(int(user2Id)) assert.NoError(t, err) expectedHealth := schema.Health{ IsHealthy: true,