From 6f6099abc666faa0b43ca85c8bee6954c51bc8cd Mon Sep 17 00:00:00 2001 From: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> Date: Fri, 29 Oct 2021 15:46:36 +0000 Subject: [PATCH] fix tests and cache bugs --- src/bot.ts | 32 ++++++++++++-- src/cache.ts | 27 ++++++++---- src/helpers/channels/clone_channel.ts | 2 +- src/helpers/channels/edit_channel.ts | 4 +- .../channels/threads/archive_thread.ts | 2 +- .../channels/threads/unarchive_thread.ts | 2 +- src/helpers/channels/threads/unlock_thread.ts | 2 +- src/helpers/guilds/create_guild.ts | 2 +- src/helpers/members/disconnect_member.ts | 2 +- src/helpers/members/move_member.ts | 2 +- src/helpers/members/send_direct_message.ts | 2 +- src/helpers/messages/add_reactions.ts | 4 +- src/helpers/messages/send_message.ts | 3 -- src/util/dispatch_requirements.ts | 6 +-- tests/messages/deleteMessage.ts | 42 +++++++++++++++++++ tests/mod.ts | 32 +++++++++----- 16 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 tests/messages/deleteMessage.ts diff --git a/src/bot.ts b/src/bot.ts index 66ef93dab..d51940782 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -253,11 +253,11 @@ export async function startBot(bot: Bot) { // SETUP bot.utils = createUtils({}); bot.transformers = createTransformers(bot.transformers || {}); - bot.helpers = createHelpers(bot.helpers || {}); + bot.helpers = createHelpers(bot); // START REST bot.rest = createRestManager({ token: bot.token, debug: bot.events.debug }); - if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot(bot); + if (!bot.botGatewayData) bot.botGatewayData = await bot.helpers.getGatewayBot(); // START WS bot.gateway = createGatewayManager({ @@ -629,7 +629,24 @@ export interface Helpers { suppressEmbeds: typeof helpers.suppressEmbeds; } -export function createHelpers(options: Partial) { +export function createHelpers( + bot: Bot, + customHelpers?: Partial, +): FinalHelpers { + const converted = {} as FinalHelpers; + for (const [name, fun] of Object.entries({ ...createBaseHelpers(customHelpers || {}) })) { + // @ts-ignore - TODO: make the types better + converted[name as keyof FinalHelpers] = ( + ...args: RemoveFirstFromTuple> + ) => + // @ts-ignore - TODO: make the types better + fun(bot, ...args); + } + + return converted; +} + +export function createBaseHelpers(options: Partial) { return { addDiscoverySubcategory: options.addDiscoverySubcategory || helpers.addDiscoverySubcategory, addReaction: options.addReaction || helpers.addReaction, @@ -1236,3 +1253,12 @@ export function createBotGatewayHandlers( INTEGRATION_DELETE: options.INTEGRATION_DELETE ?? handlers.handleIntegrationDelete, }; } + +export type RemoveFirstFromTuple = T["length"] extends 0 ? [] + : ((...b: T) => void) extends (a: any, ...b: infer I) => void ? I + : []; +export type FinalHelpers = { + [K in keyof Helpers]: ( + ...args: RemoveFirstFromTuple> + ) => ReturnType; +}; \ No newline at end of file diff --git a/src/cache.ts b/src/cache.ts index e39ca6904..e5703e263 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -1,14 +1,9 @@ -import { Bot } from "./bot.ts"; import type { DiscordenoChannel } from "./transformers/channel.ts"; import type { DiscordenoGuild } from "./transformers/guild.ts"; import type { DiscordenoMember, DiscordenoUser } from "./transformers/member.ts"; import type { DiscordenoMessage } from "./transformers/message.ts"; import { DiscordenoPresence } from "./transformers/presence.ts"; -import { PresenceUpdate } from "./types/activity/presence_update.ts"; -import { Channel } from "./types/channels/channel.ts"; import { GuildMember } from "./types/members/guild_member.ts"; -import { Message } from "./types/messages/message.ts"; -import { SnakeCasedPropertiesDeep } from "./types/util.ts"; import { Collection } from "./util/collection.ts"; export function createCache( @@ -33,7 +28,7 @@ export function createCache( throw new Error("Async cache requires a tableCreator to be passed."); } - return { + const cache = { guilds: tableCreator("guilds"), users: tableCreator("users"), members: tableCreator("members"), @@ -44,10 +39,14 @@ export function createCache( unavailableGuilds: tableCreator("unavailableGuilds"), executedSlashCommands: new Set(), } as AsyncCache; + + cache.execute = createExecute(cache); + + return cache; } if (!tableCreator) tableCreator = createTable; - return { + const cache = { guilds: tableCreator("guilds"), users: tableCreator("users"), members: tableCreator("members"), @@ -58,6 +57,10 @@ export function createCache( unavailableGuilds: tableCreator("unavailableGuilds"), executedSlashCommands: new Set(), } as Cache; + + cache.execute = createExecute(cache); + + return cache; } export type CachedDiscordenoUser = DiscordenoUser & { guilds: Map }; @@ -180,7 +183,15 @@ export function createExecute(cache: Cache | AsyncCache): CacheExecutor { }; } -export type TableNames = "channels" | "users" | "guilds" | "messages" | "presences" | "threads" | "unavailableGuilds" | "members"; +export type TableNames = + | "channels" + | "users" + | "guilds" + | "messages" + | "presences" + | "threads" + | "unavailableGuilds" + | "members"; // function messageSweeper(bot: Bot, message: DiscordenoMessage) { // // DM messages aren't needed diff --git a/src/helpers/channels/clone_channel.ts b/src/helpers/channels/clone_channel.ts index 1363011d7..06c4ba793 100644 --- a/src/helpers/channels/clone_channel.ts +++ b/src/helpers/channels/clone_channel.ts @@ -25,5 +25,5 @@ export async function cloneChannel(bot: Bot, channelId: bigint, reason?: string) }; //Create the channel (also handles permissions) - return await bot.helpers.createChannel(bot, channelToClone.guildId!, createChannelOptions, reason); + return await bot.helpers.createChannel(channelToClone.guildId!, createChannelOptions, reason); } diff --git a/src/helpers/channels/edit_channel.ts b/src/helpers/channels/edit_channel.ts index 7d3650460..abeab8115 100644 --- a/src/helpers/channels/edit_channel.ts +++ b/src/helpers/channels/edit_channel.ts @@ -98,14 +98,14 @@ function processEditChannelQueue(bot: Bot) { if (!details) return; await bot.helpers - .editChannel(bot, details.channelId, details.options) + .editChannel(details.channelId, details.options) .then((result) => details.resolve(result)) .catch(details.reject); const secondDetails = request.items.shift(); if (!secondDetails) return; await bot.helpers - .editChannel(bot, secondDetails.channelId, secondDetails.options) + .editChannel(secondDetails.channelId, secondDetails.options) .then((result) => secondDetails.resolve(result)) .catch(secondDetails.reject); return; diff --git a/src/helpers/channels/threads/archive_thread.ts b/src/helpers/channels/threads/archive_thread.ts index 42987c1a7..19f29b0d9 100644 --- a/src/helpers/channels/threads/archive_thread.ts +++ b/src/helpers/channels/threads/archive_thread.ts @@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts"; /** Sets a thread channel to be archived. */ export async function archiveThread(bot: Bot, threadId: bigint) { - return await bot.helpers.editThread(bot, threadId, { archived: true }); + return await bot.helpers.editThread(threadId, { archived: true }); } diff --git a/src/helpers/channels/threads/unarchive_thread.ts b/src/helpers/channels/threads/unarchive_thread.ts index 4bc5c14ee..0d5de45ae 100644 --- a/src/helpers/channels/threads/unarchive_thread.ts +++ b/src/helpers/channels/threads/unarchive_thread.ts @@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts"; /** Sets a thread channel to be unarchived. */ export async function unarchiveThread(bot: Bot, threadId: bigint) { - return await bot.helpers.editThread(bot, threadId, { archived: false }); + return await bot.helpers.editThread(threadId, { archived: false }); } diff --git a/src/helpers/channels/threads/unlock_thread.ts b/src/helpers/channels/threads/unlock_thread.ts index 5e3b08396..9764581ca 100644 --- a/src/helpers/channels/threads/unlock_thread.ts +++ b/src/helpers/channels/threads/unlock_thread.ts @@ -2,5 +2,5 @@ import type { Bot } from "../../../bot.ts"; /** Sets a thread channel to be unlocked. */ export async function unlockThread(bot: Bot, threadId: bigint) { - return await bot.helpers.editThread(bot, threadId, { locked: false }); + return await bot.helpers.editThread(threadId, { locked: false }); } diff --git a/src/helpers/guilds/create_guild.ts b/src/helpers/guilds/create_guild.ts index cf651652d..ccf081588 100644 --- a/src/helpers/guilds/create_guild.ts +++ b/src/helpers/guilds/create_guild.ts @@ -22,7 +22,7 @@ export async function createGuild(bot: Bot, options: CreateGuild) { // MANUALLY CACHE THE GUILD await bot.cache.guilds.set(guild.id, guild); // MANUALLY CACHE THE BOT - await bot.helpers.getMember(bot, guild.id, bot.id); + await bot.helpers.getMember(guild.id, bot.id); return guild; } diff --git a/src/helpers/members/disconnect_member.ts b/src/helpers/members/disconnect_member.ts index 71bc6897e..3eadbc25a 100644 --- a/src/helpers/members/disconnect_member.ts +++ b/src/helpers/members/disconnect_member.ts @@ -2,5 +2,5 @@ import type { Bot } from "../../bot.ts"; /** Kicks a member from a voice channel */ export function disconnectMember(bot: Bot, guildId: bigint, memberId: bigint) { - return bot.helpers.editMember(bot, guildId, memberId, { channelId: null }); + return bot.helpers.editMember(guildId, memberId, { channelId: null }); } diff --git a/src/helpers/members/move_member.ts b/src/helpers/members/move_member.ts index ce0b061ea..55a5b0e47 100644 --- a/src/helpers/members/move_member.ts +++ b/src/helpers/members/move_member.ts @@ -8,5 +8,5 @@ import type { Bot } from "../../bot.ts"; * @param channelId id of channel to move user to (if they are connected to voice) */ export function moveMember(bot: Bot, guildId: bigint, memberId: bigint, channelId: bigint) { - return bot.helpers.editMember(bot, guildId, memberId, { channelId }); + return bot.helpers.editMember(guildId, memberId, { channelId }); } diff --git a/src/helpers/members/send_direct_message.ts b/src/helpers/members/send_direct_message.ts index da7876891..b55c342f8 100644 --- a/src/helpers/members/send_direct_message.ts +++ b/src/helpers/members/send_direct_message.ts @@ -25,5 +25,5 @@ export async function sendDirectMessage(bot: Bot, memberId: bigint, content: str } // If it does exist try sending a message to this user - return await bot.helpers.sendMessage(bot, dmChannel.id, content); + return await bot.helpers.sendMessage(dmChannel.id, content); } diff --git a/src/helpers/messages/add_reactions.ts b/src/helpers/messages/add_reactions.ts index d627e7fdf..789b5f953 100644 --- a/src/helpers/messages/add_reactions.ts +++ b/src/helpers/messages/add_reactions.ts @@ -9,11 +9,11 @@ export async function addReactions( ordered = false ) { if (!ordered) { - await Promise.all(reactions.map((reaction) => bot.helpers.addReaction(bot, channelId, messageId, reaction))); + await Promise.all(reactions.map((reaction) => bot.helpers.addReaction(channelId, messageId, reaction))); } else { for (const reaction of reactions) { bot.events.debug("Running for of loop in addReactions function."); - await bot.helpers.addReaction(bot, channelId, messageId, reaction); + await bot.helpers.addReaction(channelId, messageId, reaction); } } } diff --git a/src/helpers/messages/send_message.ts b/src/helpers/messages/send_message.ts index 04c569e49..691d14812 100644 --- a/src/helpers/messages/send_message.ts +++ b/src/helpers/messages/send_message.ts @@ -1,4 +1,3 @@ -// import { cacheHandlers } from "../../cache.ts"; import { DiscordChannelTypes } from "../../types/channels/channel_types.ts"; import { Errors } from "../../types/discordeno/errors.ts"; import { DiscordAllowedMentionsTypes } from "../../types/messages/allowed_mentions_types.ts"; @@ -6,8 +5,6 @@ import type { CreateMessage } from "../../types/messages/create_message.ts"; import type { Message } from "../../types/messages/message.ts"; import type { PermissionStrings } from "../../types/permissions/permission_strings.ts"; import type { Bot } from "../../bot.ts"; -import type { SnakeCasedPropertiesDeep } from "../../types/util.ts"; -import { Embed } from "../../types/embeds/embed.ts"; /** Send a message to the channel. Requires SEND_MESSAGES permission. */ export async function sendMessage(bot: Bot, channelId: bigint, content: string | CreateMessage) { diff --git a/src/util/dispatch_requirements.ts b/src/util/dispatch_requirements.ts index 3a5d6409f..72b99bea6 100644 --- a/src/util/dispatch_requirements.ts +++ b/src/util/dispatch_requirements.ts @@ -49,7 +49,7 @@ export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload bot.events.debug(`[DISPATCH] New Guild ID has appeared: ${id} in ${data.t} event`); const rawGuild = (await bot.helpers - .getGuild(bot, id, { + .getGuild(id, { counts: true, addToCache: false, }) @@ -63,8 +63,8 @@ export async function dispatchRequirements(bot: Bot, data: DiscordGatewayPayload bot.events.debug(`[DISPATCH] Guild ID ${id} has been found. ${rawGuild.name}`); const [channels, botMember] = await Promise.all([ - bot.helpers.getChannels(bot, id, false), - bot.helpers.getMember(bot, id, bot.id, { force: true }), + bot.helpers.getChannels(id, false), + bot.helpers.getMember(id, bot.id, { force: true }), ]).catch((error) => { bot.events.debug(error); return []; diff --git a/tests/messages/deleteMessage.ts b/tests/messages/deleteMessage.ts new file mode 100644 index 000000000..8d888a3f3 --- /dev/null +++ b/tests/messages/deleteMessage.ts @@ -0,0 +1,42 @@ +import { Bot } from "../../src/bot.ts"; +import { assertExists } from "../deps.ts"; +import { delayUntil } from "../utils.ts"; + +async function ifItFailsBlameWolf(bot: Bot, channelId: bigint, reason?: string) { + const message = await bot.helpers.sendMessage(channelId, "Hello World!"); + + // Assertions + assertExists(message); + // Delay the execution by 5 seconds to allow MESSAGE_CREATE event to be processed + await delayUntil(10000, () => bot.cache.messages.has(message.id)); + // Make sure the message was created. + if (!bot.cache.messages.has(message.id)) { + throw new Error("The message seemed to be sent but it was not cached. Reason: ${reason}"); + } + + // Delete the message now + await bot.helpers.deleteMessage(channelId, message.id, reason); + + // Wait 5 seconds to give it time for MESSAGE_DELETE event + await delayUntil(10000, () => !bot.cache.messages.has(message.id)); + // Make sure it is gone from cache + if (bot.cache.messages.has(message.id)) { + throw new Error("The message should have been deleted but it is still in cache."); + } +} + +export async function deleteMessageWithoutReasonTest(bot: Bot, channelId: bigint, t: Deno.TestContext) { + console.log("⏳ [message] delete a message without a reason."); + + await ifItFailsBlameWolf(bot, channelId); + + console.log("✅ [message] delete a message without a reason."); +} + +export async function deleteMessageWithReasonTest(bot: Bot, channelId: bigint, t: Deno.TestContext) { + console.log("⏳ [message] delete a message with a reason."); + + await ifItFailsBlameWolf(bot, channelId, "with a reason"); + + console.log("✅ [message] delete a message with a reason."); +} diff --git a/tests/mod.ts b/tests/mod.ts index d51f3fb77..1cec02828 100644 --- a/tests/mod.ts +++ b/tests/mod.ts @@ -1,27 +1,33 @@ -// import { TOKEN } from "../configs.ts"; +import { TOKEN } from "../configs.ts"; import { createBot, createEventHandlers, DiscordChannelTypes, startBot, stopBot } from "../mod.ts"; import { assertEquals, assertExists } from "./deps.ts"; +import { deleteMessageWithReasonTest } from "./messages/deleteMessage.ts"; +import { deleteMessageWithoutReasonTest } from "./messages/deleteMessage.ts"; import { delayUntil } from "./utils.ts"; Deno.test("[Bot] - Starting Tests", async (t) => { let startedAt = 0; const bot = createBot({ - // token: TOKEN || Deno.env.get("DISCORD_TOKEN"), - token: Deno.env.get("DISCORD_TOKEN")!, + token: TOKEN || Deno.env.get("DISCORD_TOKEN"), + // token: Deno.env.get("DISCORD_TOKEN")!, + // TEST BOT botId: 770381961553510451n, + // DD bot + // botId: 675412054529540107n, events: createEventHandlers({ ready: () => { startedAt = Date.now(); }, - debug: console.log, + // debug: console.log, }), - intents: [], + intents: ["Guilds", "GuildMessages"], cache: { isAsync: false, }, }); await startBot(bot); + // Delay the execution to allow READY events to be processed await delayUntil(10000, () => Boolean(startedAt)); console.log("Bot online"); @@ -29,15 +35,15 @@ Deno.test("[Bot] - Starting Tests", async (t) => { // DELETE GUILDS IF LESS THAN 10 SERVERS AS SAFETY MEASURE if (bot.cache.guilds.size() <= 10) { bot.cache.guilds.forEach(async (guild) => { - if (guild.ownerId === bot.id) await bot.helpers.deleteGuild(bot, guild.id); - }) + if (guild.ownerId === bot.id) await bot.helpers.deleteGuild(guild.id); + }); } // Delay the execution to allow delete guilds to be processed await delayUntil(10000, () => Boolean(startedAt)); // CREATE ONE GUILD SO WE CAN REUSE LATER TO SAVE RATE LIMITS - const guild = await bot.helpers.createGuild(bot, { name: "Discordeno Test" }); + const guild = await bot.helpers.createGuild({ name: "Discordeno Test" }); // Assertions assertExists(guild); @@ -53,7 +59,7 @@ Deno.test("[Bot] - Starting Tests", async (t) => { // CHANNEL TESTS GROUPED await t.step("Channel related tests", async (t) => { - const channel = await bot.helpers.createChannel(bot, guild.id, { name: "Discordeno-test" }); + const channel = await bot.helpers.createChannel(guild.id, { name: "Discordeno-test" }); // Assertions assertExists(channel); @@ -61,7 +67,7 @@ Deno.test("[Bot] - Starting Tests", async (t) => { // ALL MESSAGE RELATED TESTS THAT DEPEND ON AN EXISTING CHANNEL await t.step("Message related tests", async (t) => { - const message = await bot.helpers.sendMessage(bot, channel.id, "Testing"); + const message = await bot.helpers.sendMessage(channel.id, "Testing"); // Assertions assertExists(message); @@ -72,6 +78,12 @@ Deno.test("[Bot] - Starting Tests", async (t) => { if (!bot.cache.messages.has(message.id)) { throw new Error("The message seemed to be sent but it was not cached."); } + + // CONDUCT ALL TESTS RELATED TO A MESSAGE HERE + await Promise.all([ + deleteMessageWithoutReasonTest(bot, channel.id, t), + deleteMessageWithReasonTest(bot, channel.id, t), + ]); }); });