From 374344dc26a00c9d7ff5f84f95b8771cd3b39eeb Mon Sep 17 00:00:00 2001 From: Will Hunt <will@half-shot.uk> Date: Mon, 28 Jan 2019 00:20:37 +0000 Subject: [PATCH] Test fixes and linting --- src/channelsyncroniser.ts | 2 +- src/db/roomstore.ts | 38 +++++++++++--- src/matrixroomhandler.ts | 2 +- src/provisioner.ts | 6 +-- src/store.ts | 1 - test/db/test_roomstore.ts | 48 +++++++++--------- test/test_channelsyncroniser.ts | 90 ++++++++++++++++----------------- test/test_discordbot.ts | 4 +- test/test_matrixroomhandler.ts | 27 ++++++---- tools/addRoomsToDirectory.ts | 11 ++-- tools/chanfix.ts | 22 +++----- tools/ghostfix.ts | 10 +--- 12 files changed, 138 insertions(+), 123 deletions(-) diff --git a/src/channelsyncroniser.ts b/src/channelsyncroniser.ts index f0b3e7a..9759dfa 100644 --- a/src/channelsyncroniser.ts +++ b/src/channelsyncroniser.ts @@ -279,7 +279,7 @@ export class ChannelSyncroniser { const options = this.config.channel.deleteOptions; const plumbed = entry.remote!.get("plumbed"); - this.roomStore.upsertEntry(entry); + await this.roomStore.upsertEntry(entry); if (options.ghostsLeave) { for (const member of channel.members.array()) { try { diff --git a/src/db/roomstore.ts b/src/db/roomstore.ts index 26e467a..303a11a 100644 --- a/src/db/roomstore.ts +++ b/src/db/roomstore.ts @@ -1,3 +1,18 @@ +/* +Copyright 2018 matrix-appservice-discord + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ import { Log } from "../log"; import { IDatabaseConnector } from "./connector"; @@ -11,18 +26,23 @@ const log = new Log("DbRoomStore"); * that accesses the database instead. */ -interface IRemoteRoomData { +interface IRemoteRoomData extends IRemoteRoomDataLazy { discord_guild: string; discord_channel: string; +} + +interface IRemoteRoomDataLazy { + discord_guild?: string; + discord_channel?: string; discord_name?: string|null; discord_topic?: string|null; discord_type?: string|null; discord_iconurl?: string|null; discord_iconurl_mxc?: string|null; - update_name?: number|null; - update_topic?: number|null; - update_icon?: number|null; - plumbed?: number|null; + update_name?: number|boolean|null; + update_topic?: number|boolean|null; + update_icon?: number|boolean|null; + plumbed?: number|boolean|null; } export class RemoteStoreRoom { @@ -78,7 +98,7 @@ export class DbRoomStore { public async upsertEntry(entry: IRoomStoreEntry) { const promises: Promise<void>[] = []; - // N.b. Sqlite and postgres don't really have a easy way to do upserts. + const row = (await this.db.Get("SELECT * FROM room_entries WHERE id = $id", {id: entry.id})) || {}; if (!row.id) { @@ -103,6 +123,9 @@ export class DbRoomStore { const rmIdDifferent = remoteId !== row.remote_id; // Did the room ids change? if (row.id && (mxIdDifferent || rmIdDifferent)) { + if (matrixId) { + this.entriesMatrixIdCache.delete(matrixId); + } const items: string[] = []; if (mxIdDifferent) { @@ -123,7 +146,6 @@ export class DbRoomStore { } // Matrix room doesn't store any data. - if (entry.remote) { await this.upsertRoom(entry.remote); } @@ -203,7 +225,7 @@ export class DbRoomStore { // This no-ops, because we don't store anything interesting. } - public async getEntriesByRemoteRoomData(data: {[key: string]: string}): Promise<IRoomStoreEntry[]> { + public async getEntriesByRemoteRoomData(data: IRemoteRoomDataLazy): Promise<IRoomStoreEntry[]> { const whereClaues = Object.keys(data).map((key) => { return `${key} = $${key}`; }).join(" AND "); diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts index 137ed9b..75a9e1b 100644 --- a/src/matrixroomhandler.ts +++ b/src/matrixroomhandler.ts @@ -345,7 +345,7 @@ export class MatrixRoomHandler { }); await this.provisioner.AskBridgePermission(channel, event.sender); - this.provisioner.BridgeMatrixRoom(channel, event.room_id); + await this.provisioner.BridgeMatrixRoom(channel, event.room_id); return this.bridge.getIntent().sendMessage(event.room_id, { body: "I have bridged this room to your channel", msgtype: "m.notice", diff --git a/src/provisioner.ts b/src/provisioner.ts index d2d066c..31682a3 100644 --- a/src/provisioner.ts +++ b/src/provisioner.ts @@ -33,7 +33,7 @@ export class Provisioner { this.roomStore = roomStore; } - public BridgeMatrixRoom(channel: Discord.TextChannel, roomId: string) { + public async BridgeMatrixRoom(channel: Discord.TextChannel, roomId: string) { const remote = new RemoteRoom(`discord_${channel.guild.id}_${channel.id}_bridged`); remote.set("discord_type", "text"); remote.set("discord_guild", channel.guild.id); @@ -41,10 +41,10 @@ export class Provisioner { remote.set("plumbed", true); const local = new MatrixRoom(roomId); - this.roomStore.linkRooms(local, remote); + return this.roomStore.linkRooms(local, remote); } - public UnbridgeRoom(remoteRoom: RemoteRoom) { + public async UnbridgeRoom(remoteRoom: RemoteRoom) { return this.roomStore.removeEntriesByRemoteRoomId(remoteRoom.getId()); } diff --git a/src/store.ts b/src/store.ts index 0a506a4..4e5dd9d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -97,7 +97,6 @@ export class DiscordStore { const schemaClass = require(`./db/schema/v${version}.js`).Schema; let schema: IDbSchema; if (version === SCHEMA_ROOM_STORE_REQUIRED) { // 8 requires access to the roomstore. - console.log(roomStore); schema = (new schemaClass(roomStore) as IDbSchema); } else { schema = (new schemaClass() as IDbSchema); diff --git a/test/db/test_roomstore.ts b/test/db/test_roomstore.ts index 734c6fc..4437945 100644 --- a/test/db/test_roomstore.ts +++ b/test/db/test_roomstore.ts @@ -26,7 +26,7 @@ const expect = Chai.expect; // const assert = Chai.assert; let store: DiscordStore; -describe("DiscordStore", () => { +describe("RoomStore", () => { before(async () => { store = new DiscordStore(":memory:"); await store.init(); @@ -82,38 +82,40 @@ describe("DiscordStore", () => { }); it("will replace data on an existing entry", async () => { await store.roomStore.upsertEntry({ - id: "test3", - matrix: new MatrixStoreRoom("test3_m"), - remote: new RemoteStoreRoom("test3_r", {discord_guild: "123", discord_channel: "456"}), + id: "test3.1", + matrix: new MatrixStoreRoom("test3.1_m"), + remote: new RemoteStoreRoom("test3.1_r", {discord_guild: "123", discord_channel: "456"}), }); await store.roomStore.upsertEntry({ - id: "test3", - matrix: new MatrixStoreRoom("test3_m"), - remote: new RemoteStoreRoom("test3_r", {discord_guild: "-100", discord_channel: "seventythousand"}), + id: "test3.1", + matrix: new MatrixStoreRoom("test3.1_m"), + remote: new RemoteStoreRoom("test3.1_r", {discord_guild: "-100", discord_channel: "seventythousand"}), }); - const entry = (await store.roomStore.getEntriesByMatrixId("test3_m"))[0]; - expect(entry.id).to.equal("test3"); - expect(entry.matrix!.roomId).to.equal("test3_m"); - expect(entry.remote!.roomId).to.equal("test3_r"); + const entry = (await store.roomStore.getEntriesByMatrixId("test3.1_m"))[0]; + expect(entry.id).to.equal("test3.1"); + expect(entry.matrix!.roomId).to.equal("test3.1_m"); + expect(entry.remote!.roomId).to.equal("test3.1_r"); expect(entry.remote!.get("discord_guild")).to.equal("-100"); expect(entry.remote!.get("discord_channel")).to.equal("seventythousand"); }); it("will delete data on an existing entry", async () => { await store.roomStore.upsertEntry({ - id: "test3", - matrix: new MatrixStoreRoom("test3_m"), - remote: new RemoteStoreRoom("test3_r", {discord_guild: "123", discord_channel: "456"}), + id: "test3.2", + matrix: new MatrixStoreRoom("test3.2_m"), + remote: new RemoteStoreRoom("test3.2_r", { + discord_channel: "456", discord_guild: "123", update_icon: true, + }), }); await store.roomStore.upsertEntry({ - id: "test3", - matrix: new MatrixStoreRoom("test3_m"), - remote: new RemoteStoreRoom("test3_r", {discord_guild: "123", discord_channel: "456"}), + id: "test3.2", + matrix: new MatrixStoreRoom("test3.2_m"), + remote: new RemoteStoreRoom("test3.2_r", {discord_guild: "123", discord_channel: "456"}), }); - const entry = (await store.roomStore.getEntriesByMatrixId("test3_m"))[0]; - expect(entry.id).to.equal("test3"); - expect(entry.matrix!.roomId).to.equal("test3_m"); - expect(entry.remote!.roomId).to.equal("test3_r"); - expect(entry.remote!.get("baz")).to.be.undefined; + const entry = (await store.roomStore.getEntriesByMatrixId("test3.2_m"))[0]; + expect(entry.id).to.equal("test3.2"); + expect(entry.matrix!.roomId).to.equal("test3.2_m"); + expect(entry.remote!.roomId).to.equal("test3.2_r"); + expect(entry.remote!.get("update_icon")).to.be.eq(0); }); }); describe("getEntriesByMatrixIds", () => { @@ -150,7 +152,7 @@ describe("DiscordStore", () => { }); }); describe("getEntriesByRemoteRoomData", () => { - it("will link a room", async () => { + it("will get an entry", async () => { await store.roomStore.upsertEntry({ id: "test6", matrix: new MatrixStoreRoom("test6_m"), diff --git a/test/test_channelsyncroniser.ts b/test/test_channelsyncroniser.ts index e4dc618..c54aa2f 100644 --- a/test/test_channelsyncroniser.ts +++ b/test/test_channelsyncroniser.ts @@ -26,7 +26,6 @@ import { MatrixEventProcessor, MatrixEventProcessorOpts } from "../src/matrixeve import { DiscordBridgeConfig } from "../src/config"; import { MockChannel } from "./mocks/channel"; import { Bridge, MatrixRoom, RemoteRoom } from "matrix-appservice-bridge"; - // we are a test file and thus need those /* tslint:disable:no-unused-expression max-file-line-count no-any */ @@ -109,50 +108,48 @@ function CreateChannelSync(remoteChannels: any[] = []): ChannelSyncroniser { }, }; }, - getRoomStore: () => { - REMOTECHANNEL_SET = false; - REMOTECHANNEL_REMOVED = false; - return { - getEntriesByMatrixId: (roomid) => { - const entries: any[] = []; - remoteChannels.forEach((c) => { - const mxid = c.matrix.getId(); - if (roomid === mxid) { - entries.push(c); - } - }); - return entries; - }, - getEntriesByMatrixIds: (roomids) => { - const entries = {}; - remoteChannels.forEach((c) => { - const mxid = c.matrix.getId(); - if (roomids.includes(mxid)) { - if (!entries[mxid]) { - entries[mxid] = []; - } - entries[mxid].push(c); - } - }); - return entries; - }, - getEntriesByRemoteRoomData: (data) => { - return remoteChannels.filter((c) => { - for (const d of Object.keys(data)) { - if (c.remote.get(d) !== data[d]) { - return false; - } - } - return true; - }); - }, - removeEntriesByMatrixRoomId: (room) => { - REMOTECHANNEL_REMOVED = true; - }, - upsertEntry: (room) => { - REMOTECHANNEL_SET = true; - }, - }; + }; + REMOTECHANNEL_REMOVED = false; + REMOTECHANNEL_SET = false; + const roomStore = { + getEntriesByMatrixId: (roomid) => { + const entries: any[] = []; + remoteChannels.forEach((c) => { + const mxid = c.matrix.getId(); + if (roomid === mxid) { + entries.push(c); + } + }); + return entries; + }, + getEntriesByMatrixIds: (roomids) => { + const entries = {}; + remoteChannels.forEach((c) => { + const mxid = c.matrix.getId(); + if (roomids.includes(mxid)) { + if (!entries[mxid]) { + entries[mxid] = []; + } + entries[mxid].push(c); + } + }); + return entries; + }, + getEntriesByRemoteRoomData: (data) => { + return remoteChannels.filter((c) => { + for (const d of Object.keys(data)) { + if (c.remote.get(d) !== data[d]) { + return false; + } + } + return true; + }); + }, + removeEntriesByMatrixRoomId: (room) => { + REMOTECHANNEL_REMOVED = true; + }, + upsertEntry: (room) => { + REMOTECHANNEL_SET = true; }, }; const discordbot: any = { @@ -161,7 +158,8 @@ function CreateChannelSync(remoteChannels: any[] = []): ChannelSyncroniser { const config = new DiscordBridgeConfig(); config.bridge.domain = "localhost"; config.channel.namePattern = "[Discord] :guild :name"; - return new ChannelSync(bridge as Bridge, config, discordbot); + const cs = new ChannelSync(bridge as Bridge, config, discordbot, roomStore) as ChannelSyncroniser; + return cs; } describe("ChannelSyncroniser", () => { diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts index a051813..d757a73 100644 --- a/test/test_discordbot.ts +++ b/test/test_discordbot.ts @@ -90,7 +90,7 @@ describe("DiscordBot", () => { it("should resolve when ready.", async () => { discordBot = new modDiscordBot.DiscordBot( config, - null, + { }, ); discordBot.setBridge(mockBridge); await discordBot.run(); @@ -101,7 +101,7 @@ describe("DiscordBot", () => { beforeEach( async () => { discordBot = new modDiscordBot.DiscordBot( config, - null, + { }, ); discordBot.setBridge(mockBridge); await discordBot.run(); diff --git a/test/test_matrixroomhandler.ts b/test/test_matrixroomhandler.ts index 807c0d0..39ce63e 100644 --- a/test/test_matrixroomhandler.ts +++ b/test/test_matrixroomhandler.ts @@ -97,13 +97,6 @@ function createRH(opts: any = {}) { unban: async () => { USERSUNBANNED++; }, }; }, - getRoomStore: () => { - return { - removeEntriesByMatrixRoomId: () => { - - }, - }; - }, }; const us = { JoinRoom: async () => { USERSJOINED++; }, @@ -202,7 +195,20 @@ function createRH(opts: any = {}) { }, }; const handler = new RoomHandler(bot as any, config, "@botuser:localhost", provisioner as any); - handler.setBridge(bridge); + handler.setBridge(bridge, { + getEntriesByMatrixId: (matrixId) => { + return [{ + matrix: {}, + remote: {}, + }]; + }, + linkRooms: () => { + + }, + removeEntriesByMatrixRoomId: () => { + + }, + }); return handler; } @@ -740,12 +746,11 @@ describe("MatrixRoomHandler", () => { }); }); describe("createMatrixRoom", () => { - it("will return an object", () => { + it("will return an object", async () => { const handler: any = createRH({}); const channel = new MockChannel("123", new MockGuild("456")); - const roomOpts = handler.createMatrixRoom(channel, "#test:localhost"); + const roomOpts = await handler.createMatrixRoom(channel, "#test:localhost"); expect(roomOpts.creationOpts).to.exist; - expect(roomOpts.remote).to.exist; }); }); describe("HandleDiscordCommand", () => { diff --git a/tools/addRoomsToDirectory.ts b/tools/addRoomsToDirectory.ts index d127226..200bebb 100644 --- a/tools/addRoomsToDirectory.ts +++ b/tools/addRoomsToDirectory.ts @@ -27,6 +27,7 @@ import * as usage from "command-line-usage"; import { DiscordBridgeConfig } from "../src/config"; import { Log } from "../src/log"; import { Util } from "../src/util"; +import { DiscordStore } from "../src/store"; const log = new Log("AddRoomsToDirectory"); const optionDefinitions = [ { @@ -89,20 +90,20 @@ const bridge = new Bridge({ domain: "rubbish", homeserverUrl: true, registration: true, - roomStore: options.store, }); +const discordstore = new DiscordStore(config.database ? config.database.filename : "discord.db"); + async function run() { try { - await bridge.loadDatabases(); + await discordstore.init(); } catch (e) { log.error(`Failed to load database`, e); } - // This will be broken. - let rooms = await bridge.getRoomStore().getEntriesByRemoteRoomData({ + let rooms = await discordstore.roomStore.getEntriesByRemoteRoomData({ discord_type: "text", }); - rooms = rooms.filter((r) => r.remote.get("plumbed") !== true ); + rooms = rooms.filter((r) => r.remote && r.remote.get("plumbed") !== true ); const client = clientFactory.getClientAs(); log.info(`Got ${rooms.length} rooms to set`); try { diff --git a/tools/chanfix.ts b/tools/chanfix.ts index 1fdc910..ac39a97 100644 --- a/tools/chanfix.ts +++ b/tools/chanfix.ts @@ -101,16 +101,11 @@ const bridge = new Bridge({ userStore: config.database.userStorePath, }); -// Broken -//provisioner.setStore(null); discordbot.setBridge(bridge); async function run() { - try { - await bridge.loadDatabases(); - } catch (e) { - await discordstore.init(); - } + await discordstore.init(); + provisioner.setStore(discordstore.roomStore); bridge._clientFactory = clientFactory; bridge._botClient = bridge._clientFactory.getClientAs(); bridge._botIntent = new Intent(bridge._botClient, bridge._botClient, { registered: true }); @@ -118,24 +113,23 @@ async function run() { const client = await discordbot.ClientFactory.getClient(); // first set update_icon to true if needed - // This will be broken - const mxRoomEntries = await bridge.getRoomStore().getEntriesByRemoteRoomData({ + // first set update_icon to true if needed + const mxRoomEntries = await discordstore.roomStore.getEntriesByRemoteRoomData({ update_name: true, update_topic: true, }); const promiseList: Promise<void>[] = []; mxRoomEntries.forEach((entry) => { - if (entry.remote.get("plumbed")) { + if (entry.remote && entry.remote.get("plumbed")) { return; // skipping plumbed rooms } - const updateIcon = entry.remote.get("update_icon"); + const updateIcon = entry.remote!.get("update_icon"); if (updateIcon !== undefined && updateIcon !== null) { return; // skipping because something was set manually } - entry.remote.set("update_icon", true); - // This will be broken - promiseList.push(bridge.getRoomStore().upsertEntry(entry)); + entry.remote!.set("update_icon", true); + promiseList.push(discordstore.roomStore.upsertEntry(entry)); }); await Promise.all(promiseList); diff --git a/tools/ghostfix.ts b/tools/ghostfix.ts index b634282..2da601b 100644 --- a/tools/ghostfix.ts +++ b/tools/ghostfix.ts @@ -113,17 +113,11 @@ const bridge = new Bridge({ roomStore: config.database.roomStorePath, userStore: config.database.userStorePath, }); - -// This will not work. -//provisioner.SetBridge(bridge); discordbot.setBridge(bridge); async function run() { - try { - await bridge.loadDatabases(); - } catch (e) { - await discordstore.init(); - } + await discordstore.init(); + provisioner.setStore(discordstore.roomStore); const userSync = new UserSyncroniser(bridge, config, discordbot); bridge._clientFactory = clientFactory; await discordbot.ClientFactory.init(); -- GitLab