From d03696eafaf5d77df7e71cf06cd064dfdea3bbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rancoud?= Date: Wed, 21 Feb 2024 22:26:57 +0100 Subject: [PATCH 1/2] chore: add tests on welcome run 2 --- README.md | 2 +- welcome/welcome.go | 9 +- welcome/welcome_run_test.go | 281 +++++++++++++++++++++++++++++++++++- 3 files changed, 287 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 06e0f9c..682252d 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ Then it will do another check to see if channel, role and emoji exists. Secondly it will listen two events on `onMessageReactionAdd` and `onMessageReactionRemove`. -After it will search the message in the channel. +After it will search the last 100 messages in the channel. If the message is not found then it will publish it and add a reaction to show user which emoji to use. If the message is found then it will fetch all reactions by the users and apply role. diff --git a/welcome/welcome.go b/welcome/welcome.go index a951898..e29b207 100644 --- a/welcome/welcome.go +++ b/welcome/welcome.go @@ -281,7 +281,7 @@ func (w *Manager) addMessagesToChannel() error { } for idxMessages := range w.config.Messages { - if message.Embeds[0].Title == w.config.Messages[idxMessages].Title { + if w.isSameMessageAgainstConfig(message.Embeds[0], w.config.Messages[idxMessages]) { w.config.Messages[idxMessages].ID = message.ID log.Info(). @@ -336,6 +336,12 @@ func (w *Manager) addMessagesToChannel() error { return nil } +func (w *Manager) isSameMessageAgainstConfig(messageFromDiscord *discordgo.MessageEmbed, messageFromConfig Message) bool { + return messageFromDiscord.Title == messageFromConfig.Title && + messageFromDiscord.Description == messageFromConfig.Description && + messageFromDiscord.Color == messageFromConfig.Color +} + //nolint:funlen,cyclop func (w *Manager) updateRoleBelongMessage(message Message) error { log.Info(). @@ -426,7 +432,6 @@ func (w *Manager) updateRoleBelongMessage(message Message) error { Int("count_members_not_found", len(membersNotInGuild)). Msg("Members not found in Guild") - // use constant from config file if message.CanPurgeReactions && len(users) > message.PurgeThresholdMembersReacted && len(membersNotInGuild) < message.PurgeBelowCountMembersNotInGuild { diff --git a/welcome/welcome_run_test.go b/welcome/welcome_run_test.go index 6768b1b..17eecc5 100644 --- a/welcome/welcome_run_test.go +++ b/welcome/welcome_run_test.go @@ -25,12 +25,17 @@ func TestRun(t *testing.T) { session, err := discordgo.New("fake-token") require.NoError(t, err) - session.State.Guilds = append(session.State.Guilds, &discordgo.Guild{ + session.State.GuildAdd(&discordgo.Guild{ ID: "guild-123", Name: guildName, Channels: []*discordgo.Channel{{ID: "channel-123", Name: "my-channel"}}, Emojis: []*discordgo.Emoji{{ID: "emoji-123", Name: "my-emoji-1"}}, Roles: []*discordgo.Role{{ID: "role-123", Name: "my role 1"}}, + Members: []*discordgo.Member{ + {User: &discordgo.User{ID: "user-id-456"}}, + {User: &discordgo.User{ID: "bot-123"}}, + {User: &discordgo.User{ID: "user-id-789"}, Roles: []string{"role-123"}}, + }, }) session.State.User = &discordgo.User{ @@ -104,6 +109,120 @@ func TestRun(t *testing.T) { require.Equal(t, `{"level":"info","message_id":"123","message_title":"my title 1","emoji":"my-emoji-1:emoji-123","message":"Adding Reaction to Message"}`, parts[7]) require.Equal(t, ``, parts[8]) }) + + t.Run("should find message and update roles for users which added reaction on it", func(t *testing.T) { + bufferLogs.Reset() + + data1, err := json.Marshal([]*discordgo.Message{ + { + ID: "101", + Content: "this message is skipped because author is not bot", + Author: &discordgo.User{ID: "123"}, + }, + { + ID: "102", + Content: "this message is skipped because embed is empty", + Author: &discordgo.User{ID: "bot-123"}, + }, + { + ID: "103", + Content: "this message is skipped because embed is not same against config", + Author: &discordgo.User{ID: "bot-123"}, + Embeds: []*discordgo.MessageEmbed{ + { + Title: "foo", + Description: "bar", + Color: 10, + }, + }, + }, + { + ID: "104", + Content: "this message is kept because embed is same against config", + Author: &discordgo.User{ID: "bot-123"}, + Embeds: []*discordgo.MessageEmbed{ + { + Title: "my title 1", + Description: "", + Color: 0, + }, + }, + }, + }) + require.NoError(t, err) + + recorder1 := httptest.NewRecorder() + recorder1.Header().Add("Content-Type", "application/json") + _, err = recorder1.Write(data1) + require.NoError(t, err) + + expectedResponse1 := recorder1.Result() + defer expectedResponse1.Body.Close() + + data2, err := json.Marshal([]discordgo.User{ + {ID: "456", Username: "user not in discord"}, + {ID: "bot-123", Username: "user is bot"}, + {ID: "user-id-456", Username: "user lambda 456"}, + {ID: "user-id-789", Username: "user lambda 789 already has role"}, + }) + require.NoError(t, err) + + recorder2 := httptest.NewRecorder() + recorder2.Header().Add("Content-Type", "application/json") + _, err = recorder2.Write(data2) + require.NoError(t, err) + + expectedResponse2 := recorder2.Result() + defer expectedResponse2.Body.Close() + + data3, err := json.Marshal([]discordgo.User{}) + require.NoError(t, err) + + recorder3 := httptest.NewRecorder() + recorder3.Header().Add("Content-Type", "application/json") + _, err = recorder3.Write(data3) + require.NoError(t, err) + + expectedResponse3 := recorder3.Result() + defer expectedResponse3.Body.Close() + + recorder4 := httptest.NewRecorder() + + expectedResponse4 := recorder4.Result() + defer expectedResponse4.Body.Close() + + session.Client = createClient(t, + []*http.Response{expectedResponse1, expectedResponse2, expectedResponse3, expectedResponse4}, + []requestTest{ + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages?limit=100"}, + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages/104/reactions/my-emoji-1:emoji-123?limit=100"}, + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages/104/reactions/my-emoji-1:emoji-123?after=user-id-789&limit=100"}, + {method: "PUT", host: "discord.com", uri: "/api/v9/guilds/guild-123/members/user-id-456/roles/role-123"}, + }, + ) + + err = welcomeManager.Run() + require.NoError(t, err) + + parts := strings.Split(bufferLogs.String(), "\n") + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Add"}`, parts[0]) + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Remove"}`, parts[1]) + require.Equal(t, `{"level":"info","message":"Adding messages to channel"}`, parts[2]) + require.Equal(t, `{"level":"info","channel_id":"channel-123","channel":"my-channel","message":"Getting Messages from Channel"}`, parts[3]) + //nolint:lll + require.Equal(t, `{"level":"info","message_id":"101","channel_id":"channel-123","channel":"my-channel","message":"SKIP - Message in Channel is not from bot"}`, parts[4]) + //nolint:lll + require.Equal(t, `{"level":"info","message_id":"102","channel_id":"channel-123","channel":"my-channel","message":"SKIP - Message in Channel is not an embed"}`, parts[5]) + require.Equal(t, `{"level":"info","message_title":"my title 1","message":"Message already sent -> update roles"}`, parts[6]) + //nolint:lll + require.Equal(t, `{"level":"info","message_id":"104","message_title":"my title 1","channel_id":"channel-123","channel":"my-channel","emoji":"my-emoji-1:emoji-123","message":"Getting all Reactions from Message"}`, parts[7]) + require.Equal(t, `{"level":"error","error":"state cache not found","user_id":"456","guild_id":"guild-123","message":"Could not find Member in Guild"}`, parts[8]) + require.Equal(t, `{"level":"info","user_id":"bot-123","message":"SKIP - User is the bot"}`, parts[9]) + require.Equal(t, `{"level":"info","role_id":"role-123","role":"my role 1","user_id":"user-id-456","username":"user lambda 456","message":"Add Role to User"}`, parts[10]) + require.Equal(t, `{"level":"info","user_id":"user-id-789","guild_id":"guild-123","message":"SKIP - User has already Role"}`, parts[11]) + require.Equal(t, `{"level":"info","count_members_reacted":4,"count_members_not_found":1,"message":"Members not found in Guild"}`, parts[12]) + require.Equal(t, ``, parts[13]) + }) } //nolint:funlen @@ -114,12 +233,17 @@ func TestRun_Errors(t *testing.T) { session, err := discordgo.New("fake-token") require.NoError(t, err) - session.State.Guilds = append(session.State.Guilds, &discordgo.Guild{ + session.State.GuildAdd(&discordgo.Guild{ ID: "guild-123", Name: guildName, Channels: []*discordgo.Channel{{ID: "channel-123", Name: "my-channel"}}, Emojis: []*discordgo.Emoji{{ID: "emoji-123", Name: "my-emoji-1"}}, Roles: []*discordgo.Role{{ID: "role-123", Name: "my role 1"}}, + Members: []*discordgo.Member{ + {User: &discordgo.User{ID: "user-id-456"}}, + {User: &discordgo.User{ID: "bot-123"}}, + {User: &discordgo.User{ID: "user-id-789"}, Roles: []string{"role-123"}}, + }, }) session.State.User = &discordgo.User{ @@ -287,6 +411,159 @@ func TestRun_Errors(t *testing.T) { require.Equal(t, `{"level":"error","error":"HTTP 500 Internal Server Error, ","message":"Could not add messages to channel"}`, parts[10]) require.Equal(t, ``, parts[11]) }) + + t.Run("should return error because fetching all reactions from message (MessageReactionsAll) return error", func(t *testing.T) { + bufferLogs.Reset() + + data1, err := json.Marshal([]*discordgo.Message{ + { + ID: "104", + Content: "this message is kept because embed is same against config", + Author: &discordgo.User{ID: "bot-123"}, + Embeds: []*discordgo.MessageEmbed{ + { + Title: "my title 1", + Description: "", + Color: 0, + }, + }, + }, + }) + require.NoError(t, err) + + recorder1 := httptest.NewRecorder() + recorder1.Header().Add("Content-Type", "application/json") + _, err = recorder1.Write(data1) + require.NoError(t, err) + + expectedResponse1 := recorder1.Result() + defer expectedResponse1.Body.Close() + + recorder2 := httptest.NewRecorder() + recorder2.Header().Add("Content-Type", "application/json") + _, err = recorder2.WriteString("-") + require.NoError(t, err) + + expectedResponse2 := recorder2.Result() + defer expectedResponse2.Body.Close() + + session.Client = createClient(t, + []*http.Response{expectedResponse1, expectedResponse2}, + []requestTest{ + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages?limit=100"}, + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages/104/reactions/my-emoji-1:emoji-123?limit=100"}, + }, + ) + + err = welcomeManager.Run() + require.Error(t, err) + require.ErrorContains(t, err, "json unmarshal") + + parts := strings.Split(bufferLogs.String(), "\n") + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Add"}`, parts[0]) + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Remove"}`, parts[1]) + require.Equal(t, `{"level":"info","message":"Adding messages to channel"}`, parts[2]) + require.Equal(t, `{"level":"info","channel_id":"channel-123","channel":"my-channel","message":"Getting Messages from Channel"}`, parts[3]) + require.Equal(t, `{"level":"info","message_title":"my title 1","message":"Message already sent -> update roles"}`, parts[4]) + //nolint:lll + require.Equal(t, `{"level":"info","message_id":"104","message_title":"my title 1","channel_id":"channel-123","channel":"my-channel","emoji":"my-emoji-1:emoji-123","message":"Getting all Reactions from Message"}`, parts[5]) + //nolint:lll + require.Equal(t, `{"level":"error","error":"json unmarshal","message_id":"104","channel_id":"channel-123","channel":"my-channel","emoji":"my-emoji-1:emoji-123","message":"Could not get all Reactions"}`, parts[6]) + require.Equal(t, `{"level":"error","error":"json unmarshal","message_title":"my title 1","message":"Could not update role belong to Message"}`, parts[7]) + require.Equal(t, `{"level":"error","error":"json unmarshal","message":"Could not add messages to channel"}`, parts[8]) + require.Equal(t, ``, parts[9]) + }) + + t.Run("should return error because adding role to user (GuildMemberRoleAdd) return error", func(t *testing.T) { + bufferLogs.Reset() + + data1, err := json.Marshal([]*discordgo.Message{ + { + ID: "104", + Content: "this message is kept because embed is same against config", + Author: &discordgo.User{ID: "bot-123"}, + Embeds: []*discordgo.MessageEmbed{ + { + Title: "my title 1", + Description: "", + Color: 0, + }, + }, + }, + }) + require.NoError(t, err) + + recorder1 := httptest.NewRecorder() + recorder1.Header().Add("Content-Type", "application/json") + _, err = recorder1.Write(data1) + require.NoError(t, err) + + expectedResponse1 := recorder1.Result() + defer expectedResponse1.Body.Close() + + data2, err := json.Marshal([]discordgo.User{ + {ID: "user-id-456", Username: "user lambda 456"}, + }) + require.NoError(t, err) + + recorder2 := httptest.NewRecorder() + recorder2.Header().Add("Content-Type", "application/json") + _, err = recorder2.Write(data2) + require.NoError(t, err) + + expectedResponse2 := recorder2.Result() + defer expectedResponse2.Body.Close() + + data3, err := json.Marshal([]discordgo.User{}) + require.NoError(t, err) + + recorder3 := httptest.NewRecorder() + recorder3.Header().Add("Content-Type", "application/json") + _, err = recorder3.Write(data3) + require.NoError(t, err) + + expectedResponse3 := recorder3.Result() + defer expectedResponse3.Body.Close() + + // request failed + recorder4 := httptest.NewRecorder() + recorder4.Result().Status = "500 Internal Server Error" + recorder4.Result().StatusCode = 500 + + expectedResponse4 := recorder4.Result() + defer expectedResponse4.Body.Close() + + session.Client = createClient(t, + []*http.Response{expectedResponse1, expectedResponse2, expectedResponse3, expectedResponse4}, + []requestTest{ + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages?limit=100"}, + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages/104/reactions/my-emoji-1:emoji-123?limit=100"}, + {method: "GET", host: "discord.com", uri: "/api/v9/channels/channel-123/messages/104/reactions/my-emoji-1:emoji-123?after=user-id-456&limit=100"}, + {method: "PUT", host: "discord.com", uri: "/api/v9/guilds/guild-123/members/user-id-456/roles/role-123"}, + }, + ) + + err = welcomeManager.Run() + require.Error(t, err) + require.ErrorContains(t, err, "HTTP 500 Internal Server Error") + + parts := strings.Split(bufferLogs.String(), "\n") + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Add"}`, parts[0]) + require.Equal(t, `{"level":"info","message":"Adding Handler on Message Reaction Remove"}`, parts[1]) + require.Equal(t, `{"level":"info","message":"Adding messages to channel"}`, parts[2]) + require.Equal(t, `{"level":"info","channel_id":"channel-123","channel":"my-channel","message":"Getting Messages from Channel"}`, parts[3]) + require.Equal(t, `{"level":"info","message_title":"my title 1","message":"Message already sent -> update roles"}`, parts[4]) + //nolint:lll + require.Equal(t, `{"level":"info","message_id":"104","message_title":"my title 1","channel_id":"channel-123","channel":"my-channel","emoji":"my-emoji-1:emoji-123","message":"Getting all Reactions from Message"}`, parts[5]) + //nolint:lll + require.Equal(t, `{"level":"info","role_id":"role-123","role":"my role 1","user_id":"user-id-456","username":"user lambda 456","message":"Add Role to User"}`, parts[6]) + //nolint:lll + require.Equal(t, `{"level":"error","error":"HTTP 500 Internal Server Error, ","role_id":"role-123","role":"my role 1","user_id":"user-id-456","username":"user lambda 456","message":"Could not add Role to User"}`, parts[7]) + //nolint:lll + require.Equal(t, `{"level":"error","error":"HTTP 500 Internal Server Error, ","message_title":"my title 1","message":"Could not update role belong to Message"}`, parts[8]) + require.Equal(t, `{"level":"error","error":"HTTP 500 Internal Server Error, ","message":"Could not add messages to channel"}`, parts[9]) + require.Equal(t, ``, parts[10]) + }) } type mockRoundTripper struct { From ac30f3e1ea6ffe6f060315f72bb7d15bd542360e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rancoud?= Date: Wed, 21 Feb 2024 22:31:03 +0100 Subject: [PATCH 2/2] fix lint --- welcome/welcome_run_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/welcome/welcome_run_test.go b/welcome/welcome_run_test.go index 17eecc5..f3eea14 100644 --- a/welcome/welcome_run_test.go +++ b/welcome/welcome_run_test.go @@ -25,7 +25,7 @@ func TestRun(t *testing.T) { session, err := discordgo.New("fake-token") require.NoError(t, err) - session.State.GuildAdd(&discordgo.Guild{ + err = session.State.GuildAdd(&discordgo.Guild{ ID: "guild-123", Name: guildName, Channels: []*discordgo.Channel{{ID: "channel-123", Name: "my-channel"}}, @@ -37,6 +37,7 @@ func TestRun(t *testing.T) { {User: &discordgo.User{ID: "user-id-789"}, Roles: []string{"role-123"}}, }, }) + require.NoError(t, err) session.State.User = &discordgo.User{ ID: "bot-123", @@ -216,8 +217,10 @@ func TestRun(t *testing.T) { require.Equal(t, `{"level":"info","message_title":"my title 1","message":"Message already sent -> update roles"}`, parts[6]) //nolint:lll require.Equal(t, `{"level":"info","message_id":"104","message_title":"my title 1","channel_id":"channel-123","channel":"my-channel","emoji":"my-emoji-1:emoji-123","message":"Getting all Reactions from Message"}`, parts[7]) + //nolint:lll require.Equal(t, `{"level":"error","error":"state cache not found","user_id":"456","guild_id":"guild-123","message":"Could not find Member in Guild"}`, parts[8]) require.Equal(t, `{"level":"info","user_id":"bot-123","message":"SKIP - User is the bot"}`, parts[9]) + //nolint:lll require.Equal(t, `{"level":"info","role_id":"role-123","role":"my role 1","user_id":"user-id-456","username":"user lambda 456","message":"Add Role to User"}`, parts[10]) require.Equal(t, `{"level":"info","user_id":"user-id-789","guild_id":"guild-123","message":"SKIP - User has already Role"}`, parts[11]) require.Equal(t, `{"level":"info","count_members_reacted":4,"count_members_not_found":1,"message":"Members not found in Guild"}`, parts[12]) @@ -225,7 +228,7 @@ func TestRun(t *testing.T) { }) } -//nolint:funlen +//nolint:funlen,maintidx func TestRun_Errors(t *testing.T) { var bufferLogs bytes.Buffer log.Logger = zerolog.New(&bufferLogs).Level(zerolog.TraceLevel).With().Logger() @@ -233,7 +236,7 @@ func TestRun_Errors(t *testing.T) { session, err := discordgo.New("fake-token") require.NoError(t, err) - session.State.GuildAdd(&discordgo.Guild{ + err = session.State.GuildAdd(&discordgo.Guild{ ID: "guild-123", Name: guildName, Channels: []*discordgo.Channel{{ID: "channel-123", Name: "my-channel"}}, @@ -245,6 +248,7 @@ func TestRun_Errors(t *testing.T) { {User: &discordgo.User{ID: "user-id-789"}, Roles: []string{"role-123"}}, }, }) + require.NoError(t, err) session.State.User = &discordgo.User{ ID: "bot-123", @@ -474,6 +478,7 @@ func TestRun_Errors(t *testing.T) { require.Equal(t, ``, parts[9]) }) + //nolint:bodyclose t.Run("should return error because adding role to user (GuildMemberRoleAdd) return error", func(t *testing.T) { bufferLogs.Reset()