From ef0a6aaa553b3a9a2b5e0ca95ac4698b7966f9d0 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 4 Feb 2025 10:25:55 -0600 Subject: [PATCH 01/39] Add room list to error when room not found --- packages/host/tests/helpers/mock-matrix/_server-state.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/host/tests/helpers/mock-matrix/_server-state.ts b/packages/host/tests/helpers/mock-matrix/_server-state.ts index d79edde4d6..a4445bd348 100644 --- a/packages/host/tests/helpers/mock-matrix/_server-state.ts +++ b/packages/host/tests/helpers/mock-matrix/_server-state.ts @@ -194,7 +194,11 @@ export class ServerState { // duplicate the event fully let room = event.room_id && this.#rooms.get(event.room_id); if (!room) { - throw new Error(`room ${event.room_id} does not exist`); + throw new Error( + `room ${event.room_id} does not exist, known rooms: ${Array.from( + this.#rooms.keys(), + ).join(', ')}`, + ); } let eventId = overrides?.event_id ?? this.eventId(); let matrixEvent: IEvent = { From 8fc65e8fba1b02e0123a9f89b63b846d1b2f6c7a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 4 Feb 2025 10:49:01 -0600 Subject: [PATCH 02/39] Add ability to set mock room id --- .../tests/acceptance/ai-assistant-test.gts | 5 +- packages/host/tests/acceptance/basic-test.gts | 5 +- .../tests/acceptance/code-submode-test.ts | 10 ++- .../code-submode/create-file-test.gts | 5 +- .../acceptance/code-submode/editor-test.ts | 5 +- .../acceptance/code-submode/file-tree-test.ts | 5 +- .../acceptance/code-submode/inspector-test.ts | 5 +- .../code-submode/recent-files-test.ts | 5 +- .../code-submode/schema-editor-test.ts | 5 +- .../acceptance/code-submode/spec-test.gts | 5 +- .../host/tests/acceptance/commands-test.gts | 5 +- .../acceptance/interact-submode-test.gts | 5 +- .../operator-mode-acceptance-test.gts | 5 +- .../acceptance/permissioned-realm-test.gts | 5 +- .../helpers/mock-matrix/_server-state.ts | 3 +- .../host/tests/helpers/mock-matrix/_utils.ts | 13 +++- .../send-ai-assistant-message-test.gts | 25 +++++-- .../components/ai-assistant-panel-test.gts | 65 ++++++++++++++----- .../components/room-message-test.gts | 5 +- 19 files changed, 147 insertions(+), 39 deletions(-) diff --git a/packages/host/tests/acceptance/ai-assistant-test.gts b/packages/host/tests/acceptance/ai-assistant-test.gts index cddd5bc3c8..b752b78240 100644 --- a/packages/host/tests/acceptance/ai-assistant-test.gts +++ b/packages/host/tests/acceptance/ai-assistant-test.gts @@ -114,7 +114,10 @@ module('Acceptance | AI Assistant tests', function (hooks) { setupBaseRealm(hooks); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); class Pet extends CardDef { diff --git a/packages/host/tests/acceptance/basic-test.gts b/packages/host/tests/acceptance/basic-test.gts index fb57632e1e..b2ee731d59 100644 --- a/packages/host/tests/acceptance/basic-test.gts +++ b/packages/host/tests/acceptance/basic-test.gts @@ -26,7 +26,10 @@ module('Acceptance | basic tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); let loaderService = lookupLoaderService(); diff --git a/packages/host/tests/acceptance/code-submode-test.ts b/packages/host/tests/acceptance/code-submode-test.ts index 0e180eb819..24f5ec4458 100644 --- a/packages/host/tests/acceptance/code-submode-test.ts +++ b/packages/host/tests/acceptance/code-submode-test.ts @@ -425,7 +425,10 @@ module('Acceptance | code submode tests', function (_hooks) { } hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); let realmServerService = this.owner.lookup( @@ -530,7 +533,10 @@ module('Acceptance | code submode tests', function (_hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); monacoService = this.owner.lookup( diff --git a/packages/host/tests/acceptance/code-submode/create-file-test.gts b/packages/host/tests/acceptance/code-submode/create-file-test.gts index e449a8ba18..2c27cd808c 100644 --- a/packages/host/tests/acceptance/code-submode/create-file-test.gts +++ b/packages/host/tests/acceptance/code-submode/create-file-test.gts @@ -215,7 +215,10 @@ module('Acceptance | code submode | create-file tests', function (hooks) { contents: files, })); - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); lookupNetworkService().mount( diff --git a/packages/host/tests/acceptance/code-submode/editor-test.ts b/packages/host/tests/acceptance/code-submode/editor-test.ts index b7bb400e1c..81106f14e8 100644 --- a/packages/host/tests/acceptance/code-submode/editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/editor-test.ts @@ -52,7 +52,10 @@ module('Acceptance | code submode | editor tests', function (hooks) { hooks.beforeEach(async function () { setRealmPermissions({ [testRealmURL]: ['read', 'write'] }); - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); monacoService = this.owner.lookup( diff --git a/packages/host/tests/acceptance/code-submode/file-tree-test.ts b/packages/host/tests/acceptance/code-submode/file-tree-test.ts index 34c3709e8f..f89a9466bf 100644 --- a/packages/host/tests/acceptance/code-submode/file-tree-test.ts +++ b/packages/host/tests/acceptance/code-submode/file-tree-test.ts @@ -199,7 +199,10 @@ module('Acceptance | code submode | file-tree tests', function (hooks) { hooks.beforeEach(async function () { setRealmPermissions({ [testRealmURL]: ['read', 'write'] }); - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); const numStubFiles = 100; diff --git a/packages/host/tests/acceptance/code-submode/inspector-test.ts b/packages/host/tests/acceptance/code-submode/inspector-test.ts index 2602c2923a..45220830c9 100644 --- a/packages/host/tests/acceptance/code-submode/inspector-test.ts +++ b/packages/host/tests/acceptance/code-submode/inspector-test.ts @@ -414,7 +414,10 @@ module('Acceptance | code submode | inspector tests', function (hooks) { [testRealmURL2]: ['read', 'write'], }); - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); // this seeds the loader used during index which obtains url mappings diff --git a/packages/host/tests/acceptance/code-submode/recent-files-test.ts b/packages/host/tests/acceptance/code-submode/recent-files-test.ts index 5ca89c5a64..9af6f7012f 100644 --- a/packages/host/tests/acceptance/code-submode/recent-files-test.ts +++ b/packages/host/tests/acceptance/code-submode/recent-files-test.ts @@ -190,7 +190,10 @@ module('Acceptance | code submode | recent files tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); // this seeds the loader used during index which obtains url mappings diff --git a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts index 0356ec1903..e7c4a1385a 100644 --- a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts @@ -234,7 +234,10 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); // this seeds the loader used during index which obtains url mappings diff --git a/packages/host/tests/acceptance/code-submode/spec-test.gts b/packages/host/tests/acceptance/code-submode/spec-test.gts index 79b3043806..767d697609 100644 --- a/packages/host/tests/acceptance/code-submode/spec-test.gts +++ b/packages/host/tests/acceptance/code-submode/spec-test.gts @@ -119,7 +119,10 @@ module('Spec preview', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); // this seeds the loader used during index which obtains url mappings diff --git a/packages/host/tests/acceptance/commands-test.gts b/packages/host/tests/acceptance/commands-test.gts index d97386ad80..1ce6d9e7d5 100644 --- a/packages/host/tests/acceptance/commands-test.gts +++ b/packages/host/tests/acceptance/commands-test.gts @@ -75,7 +75,10 @@ module('Acceptance | Commands tests', function (hooks) { setupBaseRealm(hooks); hooks.beforeEach(async function () { - matrixRoomId = await createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = await createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); class Pet extends CardDef { diff --git a/packages/host/tests/acceptance/interact-submode-test.gts b/packages/host/tests/acceptance/interact-submode-test.gts index 2e6c9d8b75..f7ec1d8094 100644 --- a/packages/host/tests/acceptance/interact-submode-test.gts +++ b/packages/host/tests/acceptance/interact-submode-test.gts @@ -61,7 +61,10 @@ module('Acceptance | interact submode tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); let loader = lookupLoaderService().loader; diff --git a/packages/host/tests/acceptance/operator-mode-acceptance-test.gts b/packages/host/tests/acceptance/operator-mode-acceptance-test.gts index aefcbbaefd..0367d2736e 100644 --- a/packages/host/tests/acceptance/operator-mode-acceptance-test.gts +++ b/packages/host/tests/acceptance/operator-mode-acceptance-test.gts @@ -62,7 +62,10 @@ module('Acceptance | operator mode tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); setExpiresInSec(60 * 60); diff --git a/packages/host/tests/acceptance/permissioned-realm-test.gts b/packages/host/tests/acceptance/permissioned-realm-test.gts index a06cd87971..8255cf6326 100644 --- a/packages/host/tests/acceptance/permissioned-realm-test.gts +++ b/packages/host/tests/acceptance/permissioned-realm-test.gts @@ -24,7 +24,10 @@ module('Acceptance | permissioned realm tests', function (hooks) { }); hooks.beforeEach(async function () { - matrixRoomId = createAndJoinRoom('@testuser:staging', 'room-test'); + matrixRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); setupUserSubscription(matrixRoomId); let loader = lookupLoaderService().loader; diff --git a/packages/host/tests/helpers/mock-matrix/_server-state.ts b/packages/host/tests/helpers/mock-matrix/_server-state.ts index a4445bd348..0e9d98663c 100644 --- a/packages/host/tests/helpers/mock-matrix/_server-state.ts +++ b/packages/host/tests/helpers/mock-matrix/_server-state.ts @@ -42,12 +42,13 @@ export class ServerState { sender: string, name?: string, timestamp: number = this.#now(), + id?: string, ): string { if (document.querySelector('[data-test-throw-room-error]')) { throw new Error('Intentional error thrown'); } - let roomId = `mock_room_${this.#roomCounter++}`; + let roomId = id ?? `mock_room_${this.#roomCounter++}`; if (this.#rooms.has(roomId)) { throw new Error(`room ${roomId} already exists`); diff --git a/packages/host/tests/helpers/mock-matrix/_utils.ts b/packages/host/tests/helpers/mock-matrix/_utils.ts index 24eddb578b..18284eb63a 100644 --- a/packages/host/tests/helpers/mock-matrix/_utils.ts +++ b/packages/host/tests/helpers/mock-matrix/_utils.ts @@ -65,11 +65,22 @@ export class MockUtils { setActiveRealms = (realmURLs: string[]) => { this.testState.opts!.activeRealms = realmURLs; }; - createAndJoinRoom = (sender: string, name: string, timestamp?: number) => { + createAndJoinRoom = ({ + sender, + name, + id, + timestamp, + }: { + sender: string; + name: string; + id?: string; + timestamp?: number; + }) => { let roomId = this.testState.sdk!.serverState.createRoom( sender, name, timestamp, + id, ); return roomId; }; diff --git a/packages/host/tests/integration/commands/send-ai-assistant-message-test.gts b/packages/host/tests/integration/commands/send-ai-assistant-message-test.gts index b492718483..59f55639f7 100644 --- a/packages/host/tests/integration/commands/send-ai-assistant-message-test.gts +++ b/packages/host/tests/integration/commands/send-ai-assistant-message-test.gts @@ -56,7 +56,10 @@ module('Integration | commands | send-ai-assistant-message', function (hooks) { }); test('send an ai assistant message', async function (assert) { - let roomId = createAndJoinRoom('@testuser:staging', 'room-test'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); let commandService = lookupService('command-service'); let sendAiAssistantMessageCommand = new SendAiAssistantMessageCommand( @@ -73,7 +76,10 @@ module('Integration | commands | send-ai-assistant-message', function (hooks) { }); test('send an ai assistant message with command call, not required to be called', async function (assert) { - let roomId = createAndJoinRoom('@testuser:staging', 'room-test'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); let commandService = lookupService('command-service'); let sendAiAssistantMessageCommand = new SendAiAssistantMessageCommand( @@ -96,7 +102,10 @@ module('Integration | commands | send-ai-assistant-message', function (hooks) { }); test('send an ai assistant message with command call, explicitly not required to be called', async function (assert) { - let roomId = createAndJoinRoom('@testuser:staging', 'room-test'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); let commandService = lookupService('command-service'); let sendAiAssistantMessageCommand = new SendAiAssistantMessageCommand( @@ -120,7 +129,10 @@ module('Integration | commands | send-ai-assistant-message', function (hooks) { }); test('send an ai assistant message with command call, explicitly required to be called', async function (assert) { - let roomId = createAndJoinRoom('@testuser:staging', 'room-test'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); let commandService = lookupService('command-service'); let sendAiAssistantMessageCommand = new SendAiAssistantMessageCommand( @@ -144,7 +156,10 @@ module('Integration | commands | send-ai-assistant-message', function (hooks) { }); test('multiple commands are allowed if not required to be called', async function (assert) { - let roomId = createAndJoinRoom('@testuser:staging', 'room-test'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'room-test', + }); let commandService = lookupService('command-service'); let sendAiAssistantMessageCommand = new SendAiAssistantMessageCommand( diff --git a/packages/host/tests/integration/components/ai-assistant-panel-test.gts b/packages/host/tests/integration/components/ai-assistant-panel-test.gts index f24cfccbae..6a6e1184e4 100644 --- a/packages/host/tests/integration/components/ai-assistant-panel-test.gts +++ b/packages/host/tests/integration/components/ai-assistant-panel-test.gts @@ -436,8 +436,14 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let room1Id = createAndJoinRoom('@testuser:staging', 'test room 1'); - let room2Id = createAndJoinRoom('@testuser:staging', 'test room 2'); + let room1Id = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); + let room2Id = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 2', + }); simulateRemoteMessage(room2Id, '@aibot:localhost', { msgtype: APP_BOXEL_COMMAND_MSGTYPE, body: 'Incorrect command', @@ -1178,9 +1184,15 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); - createAndJoinRoom('@testuser:staging', 'test room 0'); - let room1Id = createAndJoinRoom('@testuser:staging', 'test room 1'); - const room2Id = createAndJoinRoom('@testuser:staging', 'test room 2'); + createAndJoinRoom({ sender: '@testuser:staging', name: 'test room 0' }); + let room1Id = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); + const room2Id = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 2', + }); await settled(); await openAiAssistant(); @@ -1415,7 +1427,10 @@ module('Integration | ai-assistant-panel', function (hooks) { // Create a new room with some activity (this could happen when we will have a feature that interacts with AI outside of the AI pannel, i.e. "commands") - let anotherRoomId = createAndJoinRoom('@testuser:staging', 'Another Room'); + let anotherRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'Another Room', + }); simulateRemoteMessage( anotherRoomId, @@ -1576,7 +1591,10 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let roomId = createAndJoinRoom('@testuser:staging', 'test room 1'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); fillRoomWithReadMessages(roomId, false); await settled(); await click('[data-test-open-ai-assistant]'); @@ -1598,7 +1616,10 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let roomId = createAndJoinRoom('@testuser:staging', 'test room 1'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); fillRoomWithReadMessages(roomId); await settled(); await click('[data-test-open-ai-assistant]'); @@ -1636,7 +1657,10 @@ module('Integration | ai-assistant-panel', function (hooks) { .dom(`[data-test-enter-room='${roomId}'] [data-test-is-streaming]`) .doesNotExist(); - let anotherRoomId = createAndJoinRoom('@testuser:staging', 'Another Room'); + let anotherRoomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'Another Room', + }); let eventId3 = simulateRemoteMessage( anotherRoomId, @@ -2007,10 +2031,10 @@ module('Integration | ai-assistant-panel', function (hooks) { await click('[data-test-close-ai-assistant]'); // Create a new room with some activity - let anotherRoomId = await createAndJoinRoom( - '@testuser:staging', - 'Another Room', - ); + let anotherRoomId = await createAndJoinRoom({ + sender: '@testuser:staging', + name: 'Another Room', + }); // A message that hasn't been seen and was sent more than fifteen minutes ago must not be shown in the toast. let sixteenMinutesAgo = subMinutes(new Date(), 16); @@ -2105,7 +2129,10 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let roomId = createAndJoinRoom('@testuser:staging', 'test room 1'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); simulateRemoteMessage(roomId, '@aibot:localhost', { msgtype: APP_BOXEL_COMMAND_MSGTYPE, body: 'Changing first name to Evie', @@ -2178,7 +2205,10 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let roomId = createAndJoinRoom('@testuser:staging', 'test room 1'); + let roomId = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); simulateRemoteMessage(roomId, '@aibot:localhost', { body: 'Changing first name to Evie', msgtype: APP_BOXEL_COMMAND_MSGTYPE, @@ -2546,7 +2576,10 @@ module('Integration | ai-assistant-panel', function (hooks) { }, ); await waitFor('[data-test-person="Fadhlan"]'); - let room1Id = createAndJoinRoom('@testuser:staging', 'test room 1'); + let room1Id = createAndJoinRoom({ + sender: '@testuser:staging', + name: 'test room 1', + }); simulateRemoteMessage(room1Id, '@aibot:localhost', { msgtype: APP_BOXEL_COMMAND_MSGTYPE, diff --git a/packages/host/tests/integration/components/room-message-test.gts b/packages/host/tests/integration/components/room-message-test.gts index 0941db422b..0bb745f0cb 100644 --- a/packages/host/tests/integration/components/room-message-test.gts +++ b/packages/host/tests/integration/components/room-message-test.gts @@ -31,7 +31,10 @@ module('Integration | Component | RoomMessage', function (hooks) { }; let testScenario = { - roomId: await createAndJoinRoom('@testuser:staging', 'Test Room'), + roomId: await createAndJoinRoom({ + sender: '@testuser:staging', + name: 'Test Room', + }), message, messages: [message], isStreaming, From 9051e4e3f708a9f356a729f4930bee7099008106 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 5 Feb 2025 17:13:45 -0600 Subject: [PATCH 03/39] Add test hacks --- packages/host/app/services/matrix-service.ts | 20 +++++++++++ packages/host/app/services/message-service.ts | 30 +++++++++++++--- packages/host/app/services/realm.ts | 14 ++++++++ .../acceptance/code-submode/editor-test.ts | 9 ++++- .../acceptance/interact-submode-test.gts | 17 ++++++--- packages/host/tests/helpers/index.gts | 36 ++++++++++++++++++- packages/host/tests/helpers/mock-matrix.ts | 18 +++++++++- packages/runtime-common/realm.ts | 15 +++++++- 8 files changed, 147 insertions(+), 12 deletions(-) diff --git a/packages/host/app/services/matrix-service.ts b/packages/host/app/services/matrix-service.ts index fc54bd3e71..9bc74443bc 100644 --- a/packages/host/app/services/matrix-service.ts +++ b/packages/host/app/services/matrix-service.ts @@ -88,6 +88,7 @@ import type CommandService from './command-service'; import type LoaderService from './loader-service'; import type MatrixSDKLoader from './matrix-sdk-loader'; import type { ExtendedClient, ExtendedMatrixSDK } from './matrix-sdk-loader'; +import type MessageService from './message-service'; import type RealmService from './realm'; import type RealmServerService from './realm-server'; import type ResetService from './reset'; @@ -110,6 +111,7 @@ export default class MatrixService extends Service { @service private declare commandService: CommandService; @service private declare realm: RealmService; @service private declare matrixSdkLoader: MatrixSDKLoader; + @service private declare messageService: MessageService; @service private declare realmServer: RealmServerService; @service private declare router: RouterService; @service private declare reset: ResetService; @@ -1313,6 +1315,24 @@ export default class MatrixService extends Service { event.content?.msgtype === APP_BOXEL_REALM_SERVER_EVENT_MSGTYPE ) { await this.realmServer.handleEvent(event); + } else if ( + event.type === 'm.room.message' && + event.content?.msgtype === 'app.boxel.sse' + ) { + // FIXME provenance should be checked + console.log('received sse event', event); + let parsedEventContent = JSON.parse(event.content.body); + console.log('relayMatrixSSE', parsedEventContent); + + let realmInfoForSender = this.realm.realmOfMatrixUsername(event.sender); + if (!realmInfoForSender) { + console.log('ignoring sse event because no realm found', event); + } else { + this.messageService.relayMatrixSSE( + realmInfoForSender.url, + parsedEventContent, + ); + } } await this.addRoomEvent(event, oldEventId); diff --git a/packages/host/app/services/message-service.ts b/packages/host/app/services/message-service.ts index 46ea4b40dd..64f3f0065a 100644 --- a/packages/host/app/services/message-service.ts +++ b/packages/host/app/services/message-service.ts @@ -14,6 +14,8 @@ import type NetworkService from './network'; export default class MessageService extends Service { @tracked subscriptions: Map = new Map(); + @tracked listenerCallbacks: Map void)[]> = + new Map(); @service private declare network: NetworkService; register() { @@ -21,11 +23,13 @@ export default class MessageService extends Service { } subscribe(realmURL: string, cb: (ev: MessageEvent) => void): () => void { + console.log('subscribe', realmURL, cb); if (isTesting()) { - // we don't have a way of dealing with internal testing realm URLs when - // creating an EventSource. The EventSource API is a native browser API - // that will try to issue a network request for our testing realm URLs - // otherwise. + // only use Matrix-y callbacks in testing + if (!this.listenerCallbacks.has(realmURL)) { + this.listenerCallbacks.set(realmURL, []); + } + this.listenerCallbacks.get(realmURL)?.push(cb); return () => {}; } @@ -48,6 +52,12 @@ export default class MessageService extends Service { // TODO might want to consider making separate subscription methods so that // you can subscribe to a specific type of events instead of all of the // events... + + if (!this.listenerCallbacks.has(realmURL)) { + this.listenerCallbacks.set(realmURL, []); + } + this.listenerCallbacks.get(realmURL)?.push(cb); + eventSource.addEventListener('update', cb); eventSource.addEventListener('index', cb); return () => { @@ -55,6 +65,18 @@ export default class MessageService extends Service { eventSource.removeEventListener('index', cb); }; } + + relayMatrixSSE(realmURL: string, event: any) { + console.log('relaying matrix sse event', realmURL, event); + this.listenerCallbacks.get(realmURL)?.forEach((cb) => { + console.log('callback', cb); + let eventWithStringData = { + type: event.type, + data: JSON.stringify(event.data), + }; + cb(eventWithStringData); + }); + } } function getPersistedTokenForRealm(realmURL: string) { diff --git a/packages/host/app/services/realm.ts b/packages/host/app/services/realm.ts index bb4bc3f860..0f6e7da4ad 100644 --- a/packages/host/app/services/realm.ts +++ b/packages/host/app/services/realm.ts @@ -504,6 +504,20 @@ export default class RealmService extends Service { return undefined; } + realmOfMatrixUsername(username: string) { + // FIXME username is not fully-qualified (@experiments_realm:localhost vs experiments_realm) + username = `@${username}:localhost`; + console.log( + 'all realm usernames ', + Array.from(this.realms.values()).map((r) => r.info?.realmUserId), + ); + let realm = Array.from(this.realms.values()).find( + (r) => r.info?.realmUserId === username, + ); + console.log('realm', realm); + return realm; + } + @cached get defaultWritableRealm(): { path: string; info: RealmInfo } | null { let maybePersonalRealm = `${this.realmServer.url.href}${this.matrixService.userName}/personal/`; diff --git a/packages/host/tests/acceptance/code-submode/editor-test.ts b/packages/host/tests/acceptance/code-submode/editor-test.ts index 81106f14e8..397504698e 100644 --- a/packages/host/tests/acceptance/code-submode/editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/editor-test.ts @@ -44,11 +44,13 @@ module('Acceptance | code submode | editor tests', function (hooks) { setupLocalIndexing(hooks); setupServerSentEvents(hooks); setupOnSave(hooks); - let { setRealmPermissions, createAndJoinRoom } = setupMockMatrix(hooks, { + let mockMatrixUtils = setupMockMatrix(hooks, { loggedInAs: '@testuser:staging', activeRealms: [baseRealm.url, testRealmURL], }); + let { setRealmPermissions, createAndJoinRoom } = mockMatrixUtils; + hooks.beforeEach(async function () { setRealmPermissions({ [testRealmURL]: ['read', 'write'] }); @@ -268,6 +270,7 @@ module('Acceptance | code submode | editor tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', + realmUserId: '@test_realm:localhost', }, 'Person/john-with-bad-pet-link.json': { data: { @@ -400,6 +403,7 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(JSON.stringify(editedCard)); @@ -482,6 +486,7 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(JSON.stringify(expected)); @@ -570,6 +575,7 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { await fillIn('[data-test-field="name"] input', 'MangoXXX'); @@ -784,6 +790,7 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(expected); diff --git a/packages/host/tests/acceptance/interact-submode-test.gts b/packages/host/tests/acceptance/interact-submode-test.gts index f7ec1d8094..ee06d1991f 100644 --- a/packages/host/tests/acceptance/interact-submode-test.gts +++ b/packages/host/tests/acceptance/interact-submode-test.gts @@ -54,11 +54,13 @@ module('Acceptance | interact submode tests', function (hooks) { setupLocalIndexing(hooks); setupServerSentEvents(hooks); setupOnSave(hooks); + let mockMatrixUtils = setupMockMatrix(hooks, { + loggedInAs: '@testuser:staging', + activeRealms: [testRealmURL, testRealm2URL, testRealm3URL], + }); + let { setRealmPermissions, setActiveRealms, createAndJoinRoom } = - setupMockMatrix(hooks, { - loggedInAs: '@testuser:staging', - activeRealms: [testRealmURL, testRealm2URL, testRealm3URL], - }); + mockMatrixUtils; hooks.beforeEach(async function () { matrixRoomId = createAndJoinRoom({ @@ -351,6 +353,7 @@ module('Acceptance | interact submode tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', + realmUserId: '@test_realm:localhost', }, }, })); @@ -1759,6 +1762,7 @@ module('Acceptance | interact submode tests', function (hooks) { }); test('stack item live updates with error', async function (assert) { + console.log('test started?'); assert.expect(7); let expectedEvents = [ { @@ -1777,6 +1781,7 @@ module('Acceptance | interact submode tests', function (hooks) { }, }, ]; + console.log('visitOperatorMode'); await visitOperatorMode({ stacks: [ [ @@ -1787,6 +1792,7 @@ module('Acceptance | interact submode tests', function (hooks) { ], ], }); + console.log('visit cgomplete'); assert .dom(`[data-test-stack-card="${testRealmURL}Person/fadhlan"]`) .exists('card is displayed'); @@ -1796,9 +1802,12 @@ module('Acceptance | interact submode tests', function (hooks) { ) .doesNotExist('card error state is NOT displayed'); + console.log('about to expect events'); + await this.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { await realm.write( diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index db64cef61a..f55da07194 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -306,7 +306,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { return () => {}; } } - this.owner.register('service:message-service', MockMessageService); + // this.owner.register('service:message-service', MockMessageService); let messageService = this.owner.lookup( 'service:message-service', ) as MessageService; @@ -315,6 +315,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { this.expectEvents = async ({ assert, realm, + mockMatrixUtils, expectedEvents, expectedNumberOfEvents, onEvents, @@ -323,6 +324,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { }: { assert: Assert; realm: Realm; + mockMatrixUtils?: MockUtils; expectedEvents?: { type: string; data: Record }[]; expectedNumberOfEvents?: number; onEvents?: ( @@ -331,6 +333,38 @@ export function setupServerSentEvents(hooks: NestedHooks) { callback: () => Promise; opts?: { timeout?: number }; }): Promise => { + if (mockMatrixUtils) { + console.log('mockMatrixUtils', mockMatrixUtils); + + // FIXME shouldn’t the room be created elsewhere? and how should the username be known? + let realmSessionRoomId = `session-room-for-testuser`; + + let { createAndJoinRoom, getRoomIds, simulateRemoteMessage } = + mockMatrixUtils; + + if (!getRoomIds().includes(realmSessionRoomId)) { + createAndJoinRoom({ + sender: realm.matrixUsername, + name: realmSessionRoomId, + id: realmSessionRoomId, + }); + } + + for (let event of expectedEvents ?? []) { + simulateRemoteMessage(realmSessionRoomId, realm.matrixUsername, { + msgtype: 'app.boxel.sse', // FIXME extract/constant + format: 'app.boxel.sse-format', // FIXME does this matter? + body: JSON.stringify({ + type: event.type, + data: event.data, + }), + }); + } + + await settled(); + + return await callback(); + } let defer = new Deferred(); let events: { type: string; data: Record }[] = []; let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; diff --git a/packages/host/tests/helpers/mock-matrix.ts b/packages/host/tests/helpers/mock-matrix.ts index 99b2f4e360..d2d4e92dc2 100644 --- a/packages/host/tests/helpers/mock-matrix.ts +++ b/packages/host/tests/helpers/mock-matrix.ts @@ -26,6 +26,11 @@ export function setupMockMatrix( sdk: undefined, opts: undefined, }; + + console.log('testState', testState); + let mockUtils = new MockUtils(testState); + console.log('mockUtils', mockUtils); + hooks.beforeEach(async function () { testState.owner = this.owner; testState.opts = { ...opts }; @@ -53,6 +58,17 @@ export function setupMockMatrix( instantiate: false, }, ); + this.owner.register( + 'service:matrix-mock-utils', + { + async load() { + return mockUtils; + }, + }, + { + instantiate: false, + }, + ); if (opts.autostart) { let matrixService = this.owner.lookup( 'service:matrix-service', @@ -61,5 +77,5 @@ export function setupMockMatrix( await matrixService.start(); } }); - return new MockUtils(testState); + return mockUtils; } diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 19d4f04afd..bf8635cc6f 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -489,6 +489,11 @@ export class Realm { return this.#flushUpdateEvents; } + // FIXME this is for tests only…? + get matrixUsername() { + return this.#matrixClient.username; + } + createJWT(claims: TokenClaims, expiration: string): string { return this.#adapter.createJWT(claims, expiration, this.#realmSecretSeed); } @@ -1837,13 +1842,17 @@ export class Realm { let fileURL = this.paths.fileURL(`.realm.json`); let localPath: LocalPath = this.paths.local(fileURL); let realmConfig = await this.readFileAsText(localPath, undefined); + console.log('parse realm info realmUserId', this.#matrixClient.getUserId()); + console.log(`OR ${this.#matrixClient.username}`); let realmInfo = { name: 'Unnamed Workspace', backgroundURL: null, iconURL: null, showAsCatalog: null, visibility: await this.visibility(), - realmUserId: this.#matrixClient.getUserId()!, + // FIXME can the latter replace the former? + realmUserId: + this.#matrixClient.getUserId()! || this.#matrixClient.username, }; if (!realmConfig) { return realmInfo; @@ -1858,6 +1867,10 @@ export class Realm { realmInfo.iconURL = realmConfigJson.iconURL ?? realmInfo.iconURL; realmInfo.showAsCatalog = realmConfigJson.showAsCatalog ?? realmInfo.showAsCatalog; + // FIXME can the latter replace the former? + realmInfo.realmUserId = + realmConfigJson.realmUserId ?? + (this.#matrixClient.getUserId()! || this.#matrixClient.username); } catch (e) { this.#log.warn(`failed to parse realm config: ${e}`); } From c63fbfb7fff9e8de31c0edb394c2b5798d68cd5d Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 10:44:58 -0600 Subject: [PATCH 04/39] Add hacks to route events through Matrix in tests The adapter seems like the place but some interface changes will be needed to make it work cross-environment. --- packages/host/tests/helpers/adapter.ts | 51 +++++++++++++++++- packages/host/tests/helpers/index.gts | 75 +++++++++++++++++++------- packages/runtime-common/realm.ts | 31 +++++++---- 3 files changed, 124 insertions(+), 33 deletions(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 3fd1faa3af..0980ded158 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -22,6 +22,8 @@ import { WebMessageStream, messageCloseHandler } from './stream'; import { createJWT, testRealmURL } from '.'; +import type { MockUtils } from './mock-matrix/_utils'; + interface Dir { kind: 'directory'; contents: { [name: string]: File | Dir }; @@ -52,8 +54,14 @@ export class TestRealmAdapter implements RealmAdapter { #loader: Loader | undefined; // Will be set in the realm's constructor - needed for openFile for shimming purposes #ready = new Deferred(); #potentialModulesAndInstances: { content: any; url: URL }[] = []; - - constructor(contents: TestAdapterContents, realmURL = new URL(testRealmURL)) { + isTestAdapter: boolean = true; + owner?: Owner; + constructor( + contents: TestAdapterContents, + realmURL = new URL(testRealmURL), + owner?: Owner, + ) { + this.owner = owner; this.#paths = new RealmPaths(realmURL); let now = unixTime(Date.now()); @@ -82,6 +90,45 @@ export class TestRealmAdapter implements RealmAdapter { return this.#ready.promise; } + async sendServerEventViaMatrix(event: ServerEvents) { + console.log('sendServerEventViaMatrix', event); + + if (!this.owner) { + console.log('owner not set, skipping'); + return; + } + + let mockMatrixUtils = (await this.owner + .lookup('service:matrix-mock-utils') + .load()) as MockUtils; + + // FIXME shouldn’t the room be created elsewhere? and how should the username be known? + let realmSessionRoomId = `session-room-for-testuser`; + + let { createAndJoinRoom, getRoomIds, simulateRemoteMessage } = + mockMatrixUtils; + + // FIXME how can this be determined? Adapter doesn’t currently know + let realmMatrixUsername = 'test_realm'; + + if (!getRoomIds().includes(realmSessionRoomId)) { + createAndJoinRoom({ + sender: realmMatrixUsername, + name: realmSessionRoomId, + id: realmSessionRoomId, + }); + } + + simulateRemoteMessage(realmSessionRoomId, realmMatrixUsername, { + msgtype: 'app.boxel.sse', // FIXME extract/constant + format: 'app.boxel.sse-format', // FIXME does this matter? + body: JSON.stringify({ + type: event.type, + data: event.data, + }), + }); + } + // We are eagerly establishing shims and preparing instances to be able to be // serialized as our test realm needs to be able to serve these via the HTTP // API (internally) in order to index itself at boot diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index f55da07194..7a53d67033 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -8,6 +8,8 @@ import { import { findAll, waitUntil, waitFor, click } from '@ember/test-helpers'; import GlimmerComponent from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; + import ms from 'ms'; import { @@ -46,6 +48,7 @@ import type CardService from '@cardstack/host/services/card-service'; import type { CardSaveSubscriber } from '@cardstack/host/services/card-service'; import type LoaderService from '@cardstack/host/services/loader-service'; +import type MatrixService from '@cardstack/host/services/matrix-service'; import type MessageService from '@cardstack/host/services/message-service'; import type NetworkService from '@cardstack/host/services/network'; @@ -61,6 +64,7 @@ import { } from 'https://cardstack.com/base/card-api'; import { TestRealmAdapter } from './adapter'; +import { MockUtils } from './mock-matrix/_utils'; import percySnapshot from './percy-snapshot'; import { renderComponent } from './render-component'; import visitOperatorMode from './visit-operator-mode'; @@ -176,6 +180,7 @@ export interface TestContextWithSSE extends TestContext { expectEvents: (args: { assert: Assert; realm: Realm; + mockMatrixUtils?: MockUtils; expectedEvents?: { type: string; data: Record }[]; expectedNumberOfEvents?: number; onEvents?: (events: { type: string; data: Record }[]) => void; @@ -274,6 +279,10 @@ class MockMessageService extends Service { return () => {}; } register() {} + + relayMatrixSSE(realmURL: string, event: any) { + console.log('would relay matrix sse event', realmURL, event); + } } export function setupOnSave(hooks: NestedHooks) { @@ -287,23 +296,48 @@ export function setupOnSave(hooks: NestedHooks) { export function setupMockMessageService(hooks: NestedHooks) { hooks.beforeEach(function () { - this.owner.register('service:message-service', MockMessageService); + // this.owner.register('service:message-service', MockMessageService); }); } export function setupServerSentEvents(hooks: NestedHooks) { hooks.beforeEach(function () { this.subscribers = []; - let self = this; testOnlyResetLiveCardState(); + // FIXME to remove class MockMessageService extends Service { + @tracked subscriptions: Map = new Map(); + @tracked listenerCallbacks: Map void)[]> = + new Map(); register() { (globalThis as any)._CARDSTACK_REALM_SUBSCRIBE = this; } - subscribe(_: never, cb: (e: { type: string; data: string }) => void) { - self.subscribers.push(cb); - return () => {}; + + // FIXME duplicated from host/app/services/message-service, to be made obsolete + subscribe(realmURL: string, cb: (ev: MessageEvent) => void): () => void { + console.log('subscribe', realmURL, cb); + if (!this.listenerCallbacks.has(realmURL)) { + this.listenerCallbacks.set(realmURL, []); + } + this.listenerCallbacks.get(realmURL)?.push(cb); + + return () => { + // FIXME cleanup + }; + } + + relayMatrixSSE(realmURL: string, event: any) { + console.log('relaying matrix sse event', realmURL, event); + this.listenerCallbacks.get(realmURL)?.forEach((cb) => { + console.log('callback', cb); + let eventWithStringData = { + type: event.type, + data: JSON.stringify(event.data), + }; + console.log('eventWithStringData', eventWithStringData); + cb(eventWithStringData); + }); } } // this.owner.register('service:message-service', MockMessageService); @@ -312,6 +346,16 @@ export function setupServerSentEvents(hooks: NestedHooks) { ) as MessageService; messageService.register(); + let matrixService = this.owner.lookup( + 'service:matrix-service', + ) as MatrixService; + + // let matrixMockUtils = this.owner.lookup( + // 'service:matrix-mock-utils', + // ) as MockUtils; + + // FIXME choose an approach + this.expectEvents = async ({ assert, realm, @@ -339,8 +383,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { // FIXME shouldn’t the room be created elsewhere? and how should the username be known? let realmSessionRoomId = `session-room-for-testuser`; - let { createAndJoinRoom, getRoomIds, simulateRemoteMessage } = - mockMatrixUtils; + let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; if (!getRoomIds().includes(realmSessionRoomId)) { createAndJoinRoom({ @@ -350,20 +393,11 @@ export function setupServerSentEvents(hooks: NestedHooks) { }); } - for (let event of expectedEvents ?? []) { - simulateRemoteMessage(realmSessionRoomId, realm.matrixUsername, { - msgtype: 'app.boxel.sse', // FIXME extract/constant - format: 'app.boxel.sse-format', // FIXME does this matter? - body: JSON.stringify({ - type: event.type, - data: event.data, - }), - }); - } + let result = await callback(); + console.log('subscribers?', this.subscribers); await settled(); - - return await callback(); + return result; } let defer = new Deferred(); let events: { type: string; data: Record }[] = []; @@ -408,6 +442,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { } if (value) { let ev = getEventData(decoder.decode(value, { stream: true })); + console.log('got event', ev); if (ev) { events.push(ev); for (let subscriber of this.subscribers) { @@ -551,7 +586,7 @@ async function setupTestRealm({ ) as unknown as MockLocalIndexer; let realm: Realm; - let adapter = new TestRealmAdapter(contents, new URL(realmURL)); + let adapter = new TestRealmAdapter(contents, new URL(realmURL), owner); let indexRunner: IndexRunner = async (optsId) => { let { registerRunner, indexWriter } = runnerOptsMgr.getOptions(optsId); await localIndexer.configureRunner(registerRunner, adapter, indexWriter); diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index bf8635cc6f..9911476167 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -163,6 +163,8 @@ export interface RealmAdapter { unsubscribe(): void; setLoader?(loader: Loader): void; + + isTestAdapter?: boolean; } interface Options { @@ -2028,18 +2030,25 @@ export class Realm { } private async sendServerEvent(event: ServerEvents): Promise { - this.#log.debug( - `sending updates to ${this.listeningClients.length} clients`, - ); - let { type, data, id } = event; - let chunkArr = []; - for (let item in data) { - chunkArr.push(`"${item}": ${JSON.stringify((data as any)[item])}`); + console.log('sendServerEvent', event); + if (this.#adapter.isTestAdapter) { + console.log('overridden sendServerEvent', event); + // @ts-ignore + this.#adapter.sendServerEventViaMatrix(event); + } else { + this.#log.debug( + `sending updates to ${this.listeningClients.length} clients`, + ); + let { type, data, id } = event; + let chunkArr = []; + for (let item in data) { + chunkArr.push(`"${item}": ${JSON.stringify((data as any)[item])}`); + } + let chunk = sseToChunkData(type, `{${chunkArr.join(', ')}}`, id); + await Promise.allSettled( + this.listeningClients.map((client) => writeToStream(client, chunk)), + ); } - let chunk = sseToChunkData(type, `{${chunkArr.join(', ')}}`, id); - await Promise.allSettled( - this.listeningClients.map((client) => writeToStream(client, chunk)), - ); } private async createRequestContext(): Promise { From 83b46f6de75ba9847bd1bdce21f56fd596f84f3e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 11:45:54 -0600 Subject: [PATCH 05/39] Remove logging --- packages/host/tests/helpers/index.gts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 7a53d67033..0d2f285c70 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -394,7 +394,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { } let result = await callback(); - console.log('subscribers?', this.subscribers); await settled(); return result; From 632c90dc4219cd6220d4b6dd6a07bf63121c94e6 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 11:55:55 -0600 Subject: [PATCH 06/39] Add assertion of Matrix events --- packages/host/tests/helpers/index.gts | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 0d2f285c70..c45b96f6c6 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -393,8 +393,56 @@ export function setupServerSentEvents(hooks: NestedHooks) { }); } + let timeout = setTimeout( + () => + defer.reject( + new Error( + `expectEvent timed out, saw events ${JSON.stringify(events)}`, + ), + ), + opts?.timeout ?? 10000, + ); + let result = await callback(); + let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; + if (numOfEvents == null) { + throw new Error( + `expectEvents() must specify either 'expectedEvents' or 'expectedNumberOfEvents'`, + ); + } + + let roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); + let sseRoomEvents = roomEvents.filter( + (e) => e.type === 'app.boxel.sse', + ); + + if (expectedEvents) { + assert.deepEqual( + sseRoomEvents.forEach((e) => e.content.invalidations?.sort()), + expectedEvents.forEach((e) => e.data.invalidations?.sort()), + 'sse response is correct', + ); + } else { + assert.equal( + sseRoomEvents.length, + expectedNumberOfEvents, + 'expected number of events', + ); + } + + if (onEvents) { + // FIXME this is probably wrong + onEvents( + sseRoomEvents.map((e) => ({ + type: e.type, + data: e.content, + })), + ); + } + + clearTimeout(timeout); + await settled(); return result; } From 9eee0dc05e0512ce53b0c377e7be925c70c25fce Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 13:21:15 -0600 Subject: [PATCH 07/39] Add guard against missing Matrix mock --- packages/host/tests/helpers/adapter.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 0980ded158..795c174d2e 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -98,9 +98,14 @@ export class TestRealmAdapter implements RealmAdapter { return; } - let mockMatrixUtils = (await this.owner - .lookup('service:matrix-mock-utils') - .load()) as MockUtils; + let mockLoader = this.owner.lookup('service:mock-loader'); + + if (!mockLoader) { + console.log('mockLoader not found, skipping'); + return; + } + + let mockMatrixUtils = (await mockLoader.load()) as MockUtils; // FIXME shouldn’t the room be created elsewhere? and how should the username be known? let realmSessionRoomId = `session-room-for-testuser`; From c7ed67a7f18b7d6ed6b97fde001cad2f0a1042c6 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 13:47:00 -0600 Subject: [PATCH 08/39] Remove logging --- packages/host/tests/helpers/mock-matrix.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/host/tests/helpers/mock-matrix.ts b/packages/host/tests/helpers/mock-matrix.ts index d2d4e92dc2..e15c058df5 100644 --- a/packages/host/tests/helpers/mock-matrix.ts +++ b/packages/host/tests/helpers/mock-matrix.ts @@ -27,9 +27,7 @@ export function setupMockMatrix( opts: undefined, }; - console.log('testState', testState); let mockUtils = new MockUtils(testState); - console.log('mockUtils', mockUtils); hooks.beforeEach(async function () { testState.owner = this.owner; From b7536c86d63194dd5689388d31713579ce531bba Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 13:48:46 -0600 Subject: [PATCH 09/39] Fix service name typo --- packages/host/tests/helpers/adapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 795c174d2e..47bc59b97b 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -98,7 +98,7 @@ export class TestRealmAdapter implements RealmAdapter { return; } - let mockLoader = this.owner.lookup('service:mock-loader'); + let mockLoader = this.owner.lookup('service:matrix-mock-utils'); if (!mockLoader) { console.log('mockLoader not found, skipping'); From b8a1ea0b538aa15f33a869a7046f8951c50f2f47 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 13:51:46 -0600 Subject: [PATCH 10/39] Move Matrix setup hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This probably needs to move into another hook…? Or should test realm setup hooks error if it hasn’t been called? --- .../tests/integration/components/card-copy-test.gts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/host/tests/integration/components/card-copy-test.gts b/packages/host/tests/integration/components/card-copy-test.gts index 0cb65a3c5c..12affa8ac5 100644 --- a/packages/host/tests/integration/components/card-copy-test.gts +++ b/packages/host/tests/integration/components/card-copy-test.gts @@ -63,6 +63,12 @@ module('Integration | card-copy', function (hooks) { ); setupServerSentEvents(hooks); + setupMockMatrix(hooks, { + loggedInAs: '@testuser:staging', + activeRealms: [baseRealm.url, testRealmURL, testRealm2URL], + autostart: true, + }); + hooks.beforeEach(async function () { setCardInOperatorModeState = async ( leftCards: string[], @@ -270,12 +276,6 @@ module('Integration | card-copy', function (hooks) { ); }); - setupMockMatrix(hooks, { - loggedInAs: '@testuser:staging', - activeRealms: [baseRealm.url, testRealmURL, testRealm2URL], - autostart: true, - }); - test('copy button does not appear when there is 1 stack for single card item', async function (assert) { await setCardInOperatorModeState([ `${testRealmURL}index`, From 075fe3e57dd78cb37f7568885a5bee3d39d49b7c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Fri, 7 Feb 2025 14:14:11 -0600 Subject: [PATCH 11/39] Add missing mock Matrix setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s probably at the point that I should stop changing tests to add this setup and make it built-in…??? --- .../tests/acceptance/code-submode/schema-editor-test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts index e7c4a1385a..41e0c88b9d 100644 --- a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts @@ -26,6 +26,7 @@ import { type TestContextWithSave, } from '../../helpers'; import { setupMockMatrix } from '../../helpers/mock-matrix'; +import { MockUtils } from '../../helpers/mock-matrix/_utils'; import { setupApplicationTest } from '../../helpers/setup'; import '@cardstack/runtime-common/helpers/code-equality-assertion'; @@ -209,6 +210,7 @@ const ambiguousDisplayNamesCardSource = ` let matrixRoomId: string; module('Acceptance | code submode | schema editor tests', function (hooks) { let realm: Realm; + let mockMatrixUtils: MockUtils; async function saveField( context: TestContextWithSSE, @@ -218,6 +220,7 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { await context.expectEvents({ assert, realm, + mockMatrixUtils, expectedEvents, callback: async () => { await click('[data-test-save-field-button]'); @@ -228,11 +231,14 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { setupLocalIndexing(hooks); setupOnSave(hooks); setupServerSentEvents(hooks); - let { createAndJoinRoom } = setupMockMatrix(hooks, { + + mockMatrixUtils = setupMockMatrix(hooks, { loggedInAs: '@testuser:staging', activeRealms: [baseRealm.url, testRealmURL], }); + let { createAndJoinRoom } = mockMatrixUtils; + hooks.beforeEach(async function () { matrixRoomId = createAndJoinRoom({ sender: '@testuser:staging', @@ -326,6 +332,7 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', + realmUserId: '@test_realm:localhost', }, }, })); From 52c9a18ea168abd817326d98fe9f731b6162e26c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 09:19:15 -0700 Subject: [PATCH 12/39] Move sendServerEvents into adapter --- packages/host/tests/helpers/adapter.ts | 39 ++++++++++------------- packages/realm-server/node-realm.ts | 27 ++++++++++++++++ packages/runtime-common/realm.ts | 44 ++++++++++++++------------ 3 files changed, 66 insertions(+), 44 deletions(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 47bc59b97b..ccf1cf7e1a 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -1,3 +1,5 @@ +import type Owner from '@ember/owner'; + import { Loader, LocalPath, @@ -10,12 +12,14 @@ import { unixTime, } from '@cardstack/runtime-common'; +import { type MatrixClient } from '@cardstack/runtime-common/matrix-client'; import { FileRef, Kind, RequestContext, TokenClaims, UpdateEventData, + type ServerEvents, } from '@cardstack/runtime-common/realm'; import { WebMessageStream, messageCloseHandler } from './stream'; @@ -54,8 +58,8 @@ export class TestRealmAdapter implements RealmAdapter { #loader: Loader | undefined; // Will be set in the realm's constructor - needed for openFile for shimming purposes #ready = new Deferred(); #potentialModulesAndInstances: { content: any; url: URL }[] = []; - isTestAdapter: boolean = true; owner?: Owner; + constructor( contents: TestAdapterContents, realmURL = new URL(testRealmURL), @@ -90,7 +94,7 @@ export class TestRealmAdapter implements RealmAdapter { return this.#ready.promise; } - async sendServerEventViaMatrix(event: ServerEvents) { + async sendServerEvent(event: ServerEvents, matrixClient: MatrixClient) { console.log('sendServerEventViaMatrix', event); if (!this.owner) { @@ -107,31 +111,20 @@ export class TestRealmAdapter implements RealmAdapter { let mockMatrixUtils = (await mockLoader.load()) as MockUtils; - // FIXME shouldn’t the room be created elsewhere? and how should the username be known? - let realmSessionRoomId = `session-room-for-testuser`; - - let { createAndJoinRoom, getRoomIds, simulateRemoteMessage } = - mockMatrixUtils; + let { getRoomIds, simulateRemoteMessage } = mockMatrixUtils; - // FIXME how can this be determined? Adapter doesn’t currently know - let realmMatrixUsername = 'test_realm'; + let realmMatrixUsername = matrixClient.username; - if (!getRoomIds().includes(realmSessionRoomId)) { - createAndJoinRoom({ - sender: realmMatrixUsername, - name: realmSessionRoomId, - id: realmSessionRoomId, + for (let roomId of getRoomIds()) { + simulateRemoteMessage(roomId, realmMatrixUsername, { + msgtype: 'app.boxel.sse', // FIXME extract/constant + format: 'app.boxel.sse-format', // FIXME does this matter? + body: JSON.stringify({ + type: event.type, + data: event.data, + }), }); } - - simulateRemoteMessage(realmSessionRoomId, realmMatrixUsername, { - msgtype: 'app.boxel.sse', // FIXME extract/constant - format: 'app.boxel.sse-format', // FIXME does this matter? - body: JSON.stringify({ - type: event.type, - data: event.data, - }), - }); } // We are eagerly establishing shims and preparing instances to be able to be diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index b302f125dc..29f4fc9a6f 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -7,6 +7,7 @@ import { type ResponseWithNodeStream, type TokenClaims, } from '@cardstack/runtime-common'; +import { type MatrixClient } from '@cardstack/runtime-common/matrix-client'; import { LocalPath } from '@cardstack/runtime-common/paths'; import { ServerResponse } from 'http'; import sane, { type Watcher } from 'sane'; @@ -26,6 +27,7 @@ import { join } from 'path'; import { Duplex } from 'node:stream'; import type { RequestContext, + ServerEvents, UpdateEventData, } from '@cardstack/runtime-common/realm'; import jwt from 'jsonwebtoken'; @@ -182,6 +184,31 @@ export class NodeAdapter implements RealmAdapter { exp: number; }; } + + async sendServerEvent( + event: ServerEvents, + matrixClient: MatrixClient, + ): Promise { + let dmRooms = + (await matrixClient.getAccountData>( + 'boxel.session-rooms', + )) ?? {}; + + for (let roomId of Object.keys(dmRooms)) { + try { + await matrixClient.sendEvent(roomId, 'm.room.message', { + body: JSON.stringify({ + type: event.type, + data: event.data, + }), + msgtype: 'app.boxel.sse', + format: 'app.boxel.sse-format', + }); + } catch (e) { + console.log(`Unable to send event in room ${roomId}`, event, e); + } + } + } } export function onClose(request: Request, fn: () => void) { diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 9911476167..e7df159c20 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -164,7 +164,11 @@ export interface RealmAdapter { setLoader?(loader: Loader): void; - isTestAdapter?: boolean; + sendServerEvent( + event: ServerEvents, + matrixClient: MatrixClient, + usernames: string[], + ): Promise; } interface Options { @@ -177,7 +181,7 @@ interface UpdateItem { url: URL; } -type ServerEvents = UpdateEvent | IndexEvent | MessageEvent; +export type ServerEvents = UpdateEvent | IndexEvent | MessageEvent; interface UpdateEvent { type: 'update'; @@ -313,6 +317,16 @@ export class Realm { this.paths = new RealmPaths(new URL(url)); let { username, url: matrixURL } = matrix; this.#realmSecretSeed = secretSeed; + + // @ts-expect-error + if (!globalThis.realmUrlToSecretSeed) { + // @ts-expect-error + globalThis.realmUrlToSecretSeed = new Map(); + } + + // @ts-expect-error + globalThis.realmUrlToSecretSeed.set(this.url, secretSeed); + this.#matrixClient = new MatrixClient({ matrixURL, username, @@ -1976,7 +1990,9 @@ export class Realm { }); } + // FIXME listeningClients should go away this.listeningClients.push(writable); + this.sendServerEvent({ type: 'message', data: { count: `${this.listeningClients.length} clients` }, @@ -2030,25 +2046,11 @@ export class Realm { } private async sendServerEvent(event: ServerEvents): Promise { - console.log('sendServerEvent', event); - if (this.#adapter.isTestAdapter) { - console.log('overridden sendServerEvent', event); - // @ts-ignore - this.#adapter.sendServerEventViaMatrix(event); - } else { - this.#log.debug( - `sending updates to ${this.listeningClients.length} clients`, - ); - let { type, data, id } = event; - let chunkArr = []; - for (let item in data) { - chunkArr.push(`"${item}": ${JSON.stringify((data as any)[item])}`); - } - let chunk = sseToChunkData(type, `{${chunkArr.join(', ')}}`, id); - await Promise.allSettled( - this.listeningClients.map((client) => writeToStream(client, chunk)), - ); - } + this.#adapter.sendServerEvent( + event, + this.#matrixClient, + this.listeningUsers, + ); } private async createRequestContext(): Promise { From ccc589af0ceae27304225a883989850f0367bc24 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 09:40:49 -0700 Subject: [PATCH 13/39] Change all expectEvents to use mock matrix --- .../acceptance/code-submode/editor-test.ts | 4 - .../code-submode/schema-editor-test.ts | 1 - .../acceptance/interact-submode-test.gts | 1 - packages/host/tests/helpers/index.gts | 244 +++++++++--------- 4 files changed, 125 insertions(+), 125 deletions(-) diff --git a/packages/host/tests/acceptance/code-submode/editor-test.ts b/packages/host/tests/acceptance/code-submode/editor-test.ts index 397504698e..8060c0b33d 100644 --- a/packages/host/tests/acceptance/code-submode/editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/editor-test.ts @@ -403,7 +403,6 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(JSON.stringify(editedCard)); @@ -486,7 +485,6 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(JSON.stringify(expected)); @@ -575,7 +573,6 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { await fillIn('[data-test-field="name"] input', 'MangoXXX'); @@ -790,7 +787,6 @@ module('Acceptance | code submode | editor tests', function (hooks) { await this.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { setMonacoContent(expected); diff --git a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts index 41e0c88b9d..cbe4bf783d 100644 --- a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts @@ -220,7 +220,6 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { await context.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { await click('[data-test-save-field-button]'); diff --git a/packages/host/tests/acceptance/interact-submode-test.gts b/packages/host/tests/acceptance/interact-submode-test.gts index ee06d1991f..c493832ae8 100644 --- a/packages/host/tests/acceptance/interact-submode-test.gts +++ b/packages/host/tests/acceptance/interact-submode-test.gts @@ -1807,7 +1807,6 @@ module('Acceptance | interact submode tests', function (hooks) { await this.expectEvents({ assert, realm, - mockMatrixUtils, expectedEvents, callback: async () => { await realm.write( diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index c45b96f6c6..7bbd87106d 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -180,7 +180,6 @@ export interface TestContextWithSSE extends TestContext { expectEvents: (args: { assert: Assert; realm: Realm; - mockMatrixUtils?: MockUtils; expectedEvents?: { type: string; data: Record }[]; expectedNumberOfEvents?: number; onEvents?: (events: { type: string; data: Record }[]) => void; @@ -359,7 +358,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { this.expectEvents = async ({ assert, realm, - mockMatrixUtils, expectedEvents, expectedNumberOfEvents, onEvents, @@ -368,7 +366,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { }: { assert: Assert; realm: Realm; - mockMatrixUtils?: MockUtils; expectedEvents?: { type: string; data: Record }[]; expectedNumberOfEvents?: number; onEvents?: ( @@ -377,95 +374,31 @@ export function setupServerSentEvents(hooks: NestedHooks) { callback: () => Promise; opts?: { timeout?: number }; }): Promise => { - if (mockMatrixUtils) { - console.log('mockMatrixUtils', mockMatrixUtils); - - // FIXME shouldn’t the room be created elsewhere? and how should the username be known? - let realmSessionRoomId = `session-room-for-testuser`; - - let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; - - if (!getRoomIds().includes(realmSessionRoomId)) { - createAndJoinRoom({ - sender: realm.matrixUsername, - name: realmSessionRoomId, - id: realmSessionRoomId, - }); - } - - let timeout = setTimeout( - () => - defer.reject( - new Error( - `expectEvent timed out, saw events ${JSON.stringify(events)}`, - ), - ), - opts?.timeout ?? 10000, - ); + let defer = new Deferred(); - let result = await callback(); + let mockLoader = this.owner.lookup('service:matrix-mock-utils'); - let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; - if (numOfEvents == null) { - throw new Error( - `expectEvents() must specify either 'expectedEvents' or 'expectedNumberOfEvents'`, - ); - } - - let roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); - let sseRoomEvents = roomEvents.filter( - (e) => e.type === 'app.boxel.sse', - ); + if (!mockLoader) { + console.log('mockLoader not found, skipping'); + return; + } - if (expectedEvents) { - assert.deepEqual( - sseRoomEvents.forEach((e) => e.content.invalidations?.sort()), - expectedEvents.forEach((e) => e.data.invalidations?.sort()), - 'sse response is correct', - ); - } else { - assert.equal( - sseRoomEvents.length, - expectedNumberOfEvents, - 'expected number of events', - ); - } + let mockMatrixUtils = (await mockLoader.load()) as MockUtils; + console.log('mockMatrixUtils', mockMatrixUtils); - if (onEvents) { - // FIXME this is probably wrong - onEvents( - sseRoomEvents.map((e) => ({ - type: e.type, - data: e.content, - })), - ); - } + // FIXME shouldn’t the room be created elsewhere? and how should the username be known? + let realmSessionRoomId = `session-room-for-testuser`; - clearTimeout(timeout); + let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; - await settled(); - return result; - } - let defer = new Deferred(); - let events: { type: string; data: Record }[] = []; - let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; - if (numOfEvents == null) { - throw new Error( - `expectEvents() must specify either 'expectedEvents' or 'expectedNumberOfEvents'`, - ); - } - let response = await realm.handle( - new Request(`${realm.url}_message`, { - method: 'GET', - headers: { - Accept: 'text/event-stream', - }, - }), - ); - if (!response?.ok) { - throw new Error(`failed to connect to realm: ${response?.status}`); + if (!getRoomIds().includes(realmSessionRoomId)) { + createAndJoinRoom({ + sender: realm.matrixUsername, + name: realmSessionRoomId, + id: realmSessionRoomId, + }); } - let reader = response.body!.getReader(); + let timeout = setTimeout( () => defer.reject( @@ -475,53 +408,126 @@ export function setupServerSentEvents(hooks: NestedHooks) { ), opts?.timeout ?? 10000, ); + let result = await callback(); - let decoder = new TextDecoder(); - while (events.length < numOfEvents) { - let { done, value } = await Promise.race([ - reader.read(), - defer.promise as any, // this one always throws so type is not important - ]); - if (done) { - throw new Error( - `expected ${numOfEvents} events, saw ${events.length} events`, - ); - } - if (value) { - let ev = getEventData(decoder.decode(value, { stream: true })); - console.log('got event', ev); - if (ev) { - events.push(ev); - for (let subscriber of this.subscribers) { - let evWireFormat = { - type: ev.type, - data: JSON.stringify(ev.data), - }; - subscriber(evWireFormat); - } - } - } + + let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; + if (numOfEvents == null) { + throw new Error( + `expectEvents() must specify either 'expectedEvents' or 'expectedNumberOfEvents'`, + ); } + + let roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); + let sseRoomEvents = roomEvents.filter((e) => e.type === 'app.boxel.sse'); + if (expectedEvents) { - let eventsWithoutClientRequestId = events.map((e) => { - delete e.data.clientRequestId; - return e; - }); assert.deepEqual( - eventsWithoutClientRequestId.forEach((e) => - e.data.invalidations?.sort(), - ), + sseRoomEvents.forEach((e) => e.content.invalidations?.sort()), expectedEvents.forEach((e) => e.data.invalidations?.sort()), 'sse response is correct', ); + } else { + assert.equal( + sseRoomEvents.length, + expectedNumberOfEvents, + 'expected number of events', + ); } + if (onEvents) { - onEvents(events); + // FIXME this is probably wrong + onEvents( + sseRoomEvents.map((e) => ({ + type: e.type, + data: e.content, + })), + ); } + clearTimeout(timeout); - realm.unsubscribe(); + await settled(); return result; + + // FIXME is everything here covered? + + // let defer = new Deferred(); + // let events: { type: string; data: Record }[] = []; + // let numOfEvents = expectedEvents?.length ?? expectedNumberOfEvents; + // if (numOfEvents == null) { + // throw new Error( + // `expectEvents() must specify either 'expectedEvents' or 'expectedNumberOfEvents'`, + // ); + // } + // let response = await realm.handle( + // new Request(`${realm.url}_message`, { + // method: 'GET', + // headers: { + // Accept: 'text/event-stream', + // }, + // }), + // ); + // if (!response?.ok) { + // throw new Error(`failed to connect to realm: ${response?.status}`); + // } + // let reader = response.body!.getReader(); + // let timeout = setTimeout( + // () => + // defer.reject( + // new Error( + // `expectEvent timed out, saw events ${JSON.stringify(events)}`, + // ), + // ), + // opts?.timeout ?? 10000, + // ); + // let result = await callback(); + // let decoder = new TextDecoder(); + // while (events.length < numOfEvents) { + // let { done, value } = await Promise.race([ + // reader.read(), + // defer.promise as any, // this one always throws so type is not important + // ]); + // if (done) { + // throw new Error( + // `expected ${numOfEvents} events, saw ${events.length} events`, + // ); + // } + // if (value) { + // let ev = getEventData(decoder.decode(value, { stream: true })); + // console.log('got event', ev); + // if (ev) { + // events.push(ev); + // for (let subscriber of this.subscribers) { + // let evWireFormat = { + // type: ev.type, + // data: JSON.stringify(ev.data), + // }; + // subscriber(evWireFormat); + // } + // } + // } + // } + // if (expectedEvents) { + // let eventsWithoutClientRequestId = events.map((e) => { + // delete e.data.clientRequestId; + // return e; + // }); + // assert.deepEqual( + // eventsWithoutClientRequestId.forEach((e) => + // e.data.invalidations?.sort(), + // ), + // expectedEvents.forEach((e) => e.data.invalidations?.sort()), + // 'sse response is correct', + // ); + // } + // if (onEvents) { + // onEvents(events); + // } + // clearTimeout(timeout); + // realm.unsubscribe(); + // await settled(); + // return result; }; }); } From c04b76af4d0b4e8ec17e183fba41cb068221ca10 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 09:49:01 -0700 Subject: [PATCH 14/39] Remove some logging --- packages/host/app/services/message-service.ts | 1 - packages/host/tests/helpers/index.gts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/host/app/services/message-service.ts b/packages/host/app/services/message-service.ts index 64f3f0065a..17b148aabf 100644 --- a/packages/host/app/services/message-service.ts +++ b/packages/host/app/services/message-service.ts @@ -69,7 +69,6 @@ export default class MessageService extends Service { relayMatrixSSE(realmURL: string, event: any) { console.log('relaying matrix sse event', realmURL, event); this.listenerCallbacks.get(realmURL)?.forEach((cb) => { - console.log('callback', cb); let eventWithStringData = { type: event.type, data: JSON.stringify(event.data), diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 7bbd87106d..533152647a 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -329,7 +329,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { relayMatrixSSE(realmURL: string, event: any) { console.log('relaying matrix sse event', realmURL, event); this.listenerCallbacks.get(realmURL)?.forEach((cb) => { - console.log('callback', cb); let eventWithStringData = { type: event.type, data: JSON.stringify(event.data), From 367df2c93697b91b1d2dbf8bef9c8819f48da4f0 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 11:11:06 -0700 Subject: [PATCH 15/39] Add username uniqueness for test Matrix usernames --- packages/host/app/services/realm.ts | 3 +-- .../tests/acceptance/interact-submode-test.gts | 1 - packages/host/tests/helpers/index.gts | 16 +++++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/host/app/services/realm.ts b/packages/host/app/services/realm.ts index 0f6e7da4ad..a817f933c7 100644 --- a/packages/host/app/services/realm.ts +++ b/packages/host/app/services/realm.ts @@ -505,8 +505,6 @@ export default class RealmService extends Service { } realmOfMatrixUsername(username: string) { - // FIXME username is not fully-qualified (@experiments_realm:localhost vs experiments_realm) - username = `@${username}:localhost`; console.log( 'all realm usernames ', Array.from(this.realms.values()).map((r) => r.info?.realmUserId), @@ -515,6 +513,7 @@ export default class RealmService extends Service { (r) => r.info?.realmUserId === username, ); console.log('realm', realm); + console.log('username looked for: ', username); return realm; } diff --git a/packages/host/tests/acceptance/interact-submode-test.gts b/packages/host/tests/acceptance/interact-submode-test.gts index c493832ae8..906a51f16f 100644 --- a/packages/host/tests/acceptance/interact-submode-test.gts +++ b/packages/host/tests/acceptance/interact-submode-test.gts @@ -353,7 +353,6 @@ module('Acceptance | interact submode tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', - realmUserId: '@test_realm:localhost', }, }, })); diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 533152647a..8510479793 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -76,7 +76,10 @@ export * from '@cardstack/runtime-common/helpers/indexer'; const { sqlSchema } = ENV; type CardAPI = typeof import('https://cardstack.com/base/card-api'); -const testMatrix = { + +let testMatrixCount = 0; + +const baseTestMatrix = { url: new URL(`http://localhost:8008`), username: 'test_realm', password: 'password', @@ -652,13 +655,20 @@ async function setupTestRealm({ runnerOptsManager: runnerOptsMgr, indexRunner, virtualNetwork, - matrixURL: testMatrix.url, + matrixURL: baseTestMatrix.url, secretSeed: testRealmSecretSeed, }); + + let iteratedTestMatrix = { + ...baseTestMatrix, + username: `@${baseTestMatrix.username}-${testMatrixCount}:localhost`, + }; + testMatrixCount++; + realm = new Realm({ url: realmURL, adapter, - matrix: testMatrix, + matrix: iteratedTestMatrix, secretSeed: testRealmSecretSeed, virtualNetwork, dbAdapter, From e21fde27b61d4f64e7238b9c59d445ee12f28e5a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 11:40:36 -0700 Subject: [PATCH 16/39] Fix test extraction of SSE Matrix events --- packages/host/tests/helpers/index.gts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 8510479793..110ad5b2e6 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -421,7 +421,9 @@ export function setupServerSentEvents(hooks: NestedHooks) { } let roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); - let sseRoomEvents = roomEvents.filter((e) => e.type === 'app.boxel.sse'); + let sseRoomEvents = roomEvents.filter( + (e) => e.content?.msgtype === 'app.boxel.sse', + ); if (expectedEvents) { assert.deepEqual( From 4441d3186e22fda58dda66dbf997afe232de7c07 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 11:44:00 -0700 Subject: [PATCH 17/39] Fix events passed to onEvents --- packages/host/tests/helpers/index.gts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 110ad5b2e6..2879b773cb 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -440,13 +440,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { } if (onEvents) { - // FIXME this is probably wrong - onEvents( - sseRoomEvents.map((e) => ({ - type: e.type, - data: e.content, - })), - ); + onEvents(sseRoomEvents.map((e) => JSON.parse(e.content.body))); } clearTimeout(timeout); From bf8dc462d1caca8999c56bd52c6434d1643731e2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 13:02:29 -0700 Subject: [PATCH 18/39] Fix logging of received events --- packages/host/tests/helpers/index.gts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 2879b773cb..e04c1d717c 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -401,11 +401,13 @@ export function setupServerSentEvents(hooks: NestedHooks) { }); } + let roomEvents: MatrixEvent[] = []; + let timeout = setTimeout( () => defer.reject( new Error( - `expectEvent timed out, saw events ${JSON.stringify(events)}`, + `expectEvent timed out, saw events ${JSON.stringify(roomEvents)}`, ), ), opts?.timeout ?? 10000, @@ -420,7 +422,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { ); } - let roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); + roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); let sseRoomEvents = roomEvents.filter( (e) => e.content?.msgtype === 'app.boxel.sse', ); From e3c7f43ea70160b6baae206903dd8fe0f1cfa26a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 13:12:28 -0700 Subject: [PATCH 19/39] Remove extra assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was causing the count to be off, the original didn’t have an assertion, just an error. --- packages/host/tests/helpers/index.gts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index e04c1d717c..44a440d32f 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -434,11 +434,11 @@ export function setupServerSentEvents(hooks: NestedHooks) { 'sse response is correct', ); } else { - assert.equal( - sseRoomEvents.length, - expectedNumberOfEvents, - 'expected number of events', - ); + if (expectedNumberOfEvents !== sseRoomEvents.length) { + throw new Error( + `expected ${expectedNumberOfEvents} events, saw ${sseRoomEvents.length} events`, + ); + } } if (onEvents) { From 27dc76ed7662e17fae83bcd3d90a58e7fd02ed99 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 13:22:55 -0700 Subject: [PATCH 20/39] Remove traces of listeningUsers --- packages/runtime-common/realm.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index e7df159c20..20bb559aa3 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -167,7 +167,6 @@ export interface RealmAdapter { sendServerEvent( event: ServerEvents, matrixClient: MatrixClient, - usernames: string[], ): Promise; } @@ -2046,11 +2045,7 @@ export class Realm { } private async sendServerEvent(event: ServerEvents): Promise { - this.#adapter.sendServerEvent( - event, - this.#matrixClient, - this.listeningUsers, - ); + this.#adapter.sendServerEvent(event, this.#matrixClient); } private async createRequestContext(): Promise { From 84f02e37b8dc9b3af6557c431c8097ab89866345 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 13:25:39 -0700 Subject: [PATCH 21/39] Remove unused identifiers --- packages/runtime-common/realm.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/runtime-common/realm.ts b/packages/runtime-common/realm.ts index 20bb559aa3..1c5d9af36e 100644 --- a/packages/runtime-common/realm.ts +++ b/packages/runtime-common/realm.ts @@ -45,7 +45,6 @@ import { fileContentToText, readFileAsText, getFileWithFallbacks, - writeToStream, waitForClose, type TextFileRef, } from './stream'; @@ -2147,14 +2146,6 @@ export interface CardDefinitionResource { }; } -function sseToChunkData(type: string, data: string, id?: string): string { - let info = [`event: ${type}`, `data: ${data}`]; - if (id) { - info.push(`id: ${id}`); - } - return info.join('\n') + '\n\n'; -} - function assertRealmPermissions( realmPermissions: any, ): asserts realmPermissions is RealmPermissions { From 72b80bdaf9ef93f6b65352514f2da7d6ffa306ed Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 14:49:48 -0700 Subject: [PATCH 22/39] Add hackish workaround to remove unstable property I hate it??? But what is to be done. --- .../realm-indexing-and-querying-test.gts | 69 ++++++++++++------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/packages/host/tests/integration/realm-indexing-and-querying-test.gts b/packages/host/tests/integration/realm-indexing-and-querying-test.gts index ff27ba3315..ed814e5db4 100644 --- a/packages/host/tests/integration/realm-indexing-and-querying-test.gts +++ b/packages/host/tests/integration/realm-indexing-and-querying-test.gts @@ -48,6 +48,25 @@ const testModuleRealm = 'http://localhost:4202/test/'; let loader: Loader; +function stripRealmUserId(card: any) { + let strippedCard = { ...card }; + delete strippedCard?.data?.meta?.realmInfo?.realmUserId; + delete strippedCard?.meta?.realmInfo?.realmUserId; + + if (strippedCard?.included) { + strippedCard.included = strippedCard.included.map((card: any) => { + delete card.meta.realmInfo.realmUserId; + return card; + }); + } + + return strippedCard; +} + +function stripRealmUserIds(cards: any[]) { + return cards.map((card) => stripRealmUserId(card)); +} + module(`Integration | realm indexing and querying`, function (hooks) { setupRenderingTest(hooks); setupBaseRealm(hooks); @@ -91,7 +110,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); let queryEngine = realm.realmIndexQueryEngine; let { data: cards } = await queryEngine.search({}); - assert.deepEqual(cards, [ + assert.deepEqual(stripRealmUserIds(cards), [ { id: `${testRealmURL}empty`, type: 'card', @@ -260,7 +279,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Pet/mango`), ); if (mango?.type === 'doc') { - assert.deepEqual(mango.doc.data, { + assert.deepEqual(stripRealmUserId(mango.doc.data), { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -348,7 +367,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { // we see the "production" version of this card while it is being indexed delete entry.doc.data.meta.lastModified; delete entry.doc.data.meta.resourceCreatedAt; - assert.deepEqual(entry.doc.data, { + assert.deepEqual(stripRealmUserId(entry.doc.data), { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -392,7 +411,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { // we see the "production" version of this card while it is being indexed delete entry.doc.data.meta.lastModified; delete entry.doc.data.meta.resourceCreatedAt; - assert.deepEqual(entry.doc.data, { + assert.deepEqual(stripRealmUserId(entry.doc.data), { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -475,7 +494,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Pet/mango`), ); if (mango?.type === 'doc') { - assert.deepEqual(mango.doc.data, { + assert.deepEqual(stripRealmUserId(mango.doc.data), { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -561,7 +580,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { let indexer = realm.realmIndexQueryEngine; let mango = await indexer.cardDocument(new URL(`${testRealmURL}Pet/mango`)); if (mango?.type === 'doc') { - assert.deepEqual(mango.doc.data, { + assert.deepEqual(stripRealmUserId(mango.doc.data), { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -638,7 +657,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}person-spec`), ); if (entry?.type === 'doc') { - assert.deepEqual(entry.doc.data, { + assert.deepEqual(stripRealmUserId(entry.doc.data), { id: `${testRealmURL}person-spec`, type: 'card', links: { @@ -1602,7 +1621,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (vendor?.type === 'doc') { - assert.deepEqual(vendor.doc, { + assert.deepEqual(stripRealmUserId(vendor.doc), { data: { id: `${testRealmURL}Vendor/vendor1`, type: 'card', @@ -2101,7 +2120,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (hassan?.type === 'doc') { - assert.deepEqual(hassan.doc.data, { + assert.deepEqual(stripRealmUserId(hassan.doc.data), { id: `${testRealmURL}PetPerson/hassan`, type: 'card', links: { self: `${testRealmURL}PetPerson/hassan` }, @@ -2141,7 +2160,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { realmURL: 'http://test-realm/test/', }, }); - assert.deepEqual(hassan.doc.included, [ + assert.deepEqual(stripRealmUserIds(hassan.doc.included), [ { id: `${testRealmURL}Pet/mango`, type: 'card', @@ -2201,7 +2220,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}PetPerson/hassan`), ); if (hassanEntry) { - assert.deepEqual(hassanEntry.searchDoc, { + assert.deepEqual(stripRealmUserId(hassanEntry.searchDoc), { _cardType: 'Pet Person', id: `${testRealmURL}PetPerson/hassan`, firstName: 'Hassan', @@ -2263,7 +2282,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (card?.type === 'doc') { - assert.deepEqual(card.doc, { + assert.deepEqual(stripRealmUserId(card.doc), { data: { id: `${testRealmURL}PetPerson/burcu`, type: 'card', @@ -2306,7 +2325,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}PetPerson/burcu`), ); if (entry) { - assert.deepEqual(entry.searchDoc, { + assert.deepEqual(stripRealmUserId(entry.searchDoc), { _cardType: 'Pet Person', id: `${testRealmURL}PetPerson/burcu`, firstName: 'Burcu', @@ -2380,7 +2399,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (spec?.type === 'doc') { - assert.deepEqual(spec.doc.data, { + assert.deepEqual(stripRealmUserId(spec.doc.data), { id: `${testRealmURL}pet-person-spec`, type: 'card', links: { self: `${testRealmURL}pet-person-spec` }, @@ -2533,7 +2552,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Friend/hassan`), ); if (hassan?.type === 'doc') { - assert.deepEqual(hassan.doc.data, { + assert.deepEqual(stripRealmUserId(hassan.doc.data), { id: `${testRealmURL}Friend/hassan`, type: 'card', links: { @@ -2579,7 +2598,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Friend/hassan`), ); if (hassanEntry) { - assert.deepEqual(hassanEntry.searchDoc, { + assert.deepEqual(stripRealmUserId(hassanEntry.searchDoc), { _cardType: 'Friend', id: `${testRealmURL}Friend/hassan`, firstName: 'Hassan', @@ -2666,7 +2685,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (hassan?.type === 'doc') { - assert.deepEqual(hassan.doc, { + assert.deepEqual(stripRealmUserId(hassan.doc), { data: { id: `${testRealmURL}Friend/hassan`, type: 'card', @@ -2784,7 +2803,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (mango?.type === 'doc') { - assert.deepEqual(mango.doc, { + assert.deepEqual(stripRealmUserId(mango.doc), { data: { id: `${testRealmURL}Friend/mango`, type: 'card', @@ -2932,7 +2951,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (hassan?.type === 'doc') { - assert.deepEqual(hassan.doc, { + assert.deepEqual(stripRealmUserId(hassan.doc), { data: { id: `${testRealmURL}Friend/hassan`, type: 'card', @@ -3056,7 +3075,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (hassan?.type === 'doc') { assert.deepEqual( - hassan.doc.data, + stripRealmUserId(hassan.doc.data), { id: hassanID, type: 'card', @@ -3091,7 +3110,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); assert.deepEqual( - hassan.doc.included, + stripRealmUserIds(hassan.doc.included), [ { id: mangoID, @@ -3190,7 +3209,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (mango?.type === 'doc') { assert.deepEqual( - mango.doc.data, + stripRealmUserId(mango.doc.data), { id: mangoID, type: 'card', @@ -3220,7 +3239,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { 'mango doc.data is correct', ); assert.deepEqual( - mango.doc.included, + stripRealmUserIds(mango.doc.included), [ { id: hassanID, @@ -3329,7 +3348,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (vanGogh?.type === 'doc') { assert.deepEqual( - vanGogh.doc.data, + stripRealmUserId(vanGogh.doc.data), { id: vanGoghID, type: 'card', @@ -3359,7 +3378,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { 'vanGogh doc.data is correct', ); assert.deepEqual( - vanGogh.doc.included, + stripRealmUserIds(vanGogh.doc.included), [ { id: hassanID, From 49b9540ef91d22de9bec269ee82f21ade1385ecd Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 10 Feb 2025 15:04:21 -0700 Subject: [PATCH 23/39] Fix some type errors --- packages/host/tests/helpers/index.gts | 87 +-------------------------- 1 file changed, 2 insertions(+), 85 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 44a440d32f..cb2d8a0ca1 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -8,8 +8,7 @@ import { import { findAll, waitUntil, waitFor, click } from '@ember/test-helpers'; import GlimmerComponent from '@glimmer/component'; -import { tracked } from '@glimmer/tracking'; - +import { MatrixEvent } from 'matrix-js-sdk'; import ms from 'ms'; import { @@ -48,7 +47,6 @@ import type CardService from '@cardstack/host/services/card-service'; import type { CardSaveSubscriber } from '@cardstack/host/services/card-service'; import type LoaderService from '@cardstack/host/services/loader-service'; -import type MatrixService from '@cardstack/host/services/matrix-service'; import type MessageService from '@cardstack/host/services/message-service'; import type NetworkService from '@cardstack/host/services/network'; @@ -276,17 +274,6 @@ export function setupLocalIndexing(hooks: NestedHooks) { }); } -class MockMessageService extends Service { - subscribe() { - return () => {}; - } - register() {} - - relayMatrixSSE(realmURL: string, event: any) { - console.log('would relay matrix sse event', realmURL, event); - } -} - export function setupOnSave(hooks: NestedHooks) { hooks.beforeEach(function () { let cardService = this.owner.lookup('service:card-service') as CardService; @@ -296,67 +283,16 @@ export function setupOnSave(hooks: NestedHooks) { }); } -export function setupMockMessageService(hooks: NestedHooks) { - hooks.beforeEach(function () { - // this.owner.register('service:message-service', MockMessageService); - }); -} - export function setupServerSentEvents(hooks: NestedHooks) { hooks.beforeEach(function () { this.subscribers = []; testOnlyResetLiveCardState(); - // FIXME to remove - class MockMessageService extends Service { - @tracked subscriptions: Map = new Map(); - @tracked listenerCallbacks: Map void)[]> = - new Map(); - register() { - (globalThis as any)._CARDSTACK_REALM_SUBSCRIBE = this; - } - - // FIXME duplicated from host/app/services/message-service, to be made obsolete - subscribe(realmURL: string, cb: (ev: MessageEvent) => void): () => void { - console.log('subscribe', realmURL, cb); - if (!this.listenerCallbacks.has(realmURL)) { - this.listenerCallbacks.set(realmURL, []); - } - this.listenerCallbacks.get(realmURL)?.push(cb); - - return () => { - // FIXME cleanup - }; - } - - relayMatrixSSE(realmURL: string, event: any) { - console.log('relaying matrix sse event', realmURL, event); - this.listenerCallbacks.get(realmURL)?.forEach((cb) => { - let eventWithStringData = { - type: event.type, - data: JSON.stringify(event.data), - }; - console.log('eventWithStringData', eventWithStringData); - cb(eventWithStringData); - }); - } - } - // this.owner.register('service:message-service', MockMessageService); let messageService = this.owner.lookup( 'service:message-service', ) as MessageService; messageService.register(); - let matrixService = this.owner.lookup( - 'service:matrix-service', - ) as MatrixService; - - // let matrixMockUtils = this.owner.lookup( - // 'service:matrix-mock-utils', - // ) as MockUtils; - - // FIXME choose an approach - this.expectEvents = async ({ assert, realm, @@ -378,15 +314,8 @@ export function setupServerSentEvents(hooks: NestedHooks) { }): Promise => { let defer = new Deferred(); - let mockLoader = this.owner.lookup('service:matrix-mock-utils'); - - if (!mockLoader) { - console.log('mockLoader not found, skipping'); - return; - } - + let mockLoader = this.owner.lookup('service:matrix-mock-utils') as any; let mockMatrixUtils = (await mockLoader.load()) as MockUtils; - console.log('mockMatrixUtils', mockMatrixUtils); // FIXME shouldn’t the room be created elsewhere? and how should the username be known? let realmSessionRoomId = `session-room-for-testuser`; @@ -532,18 +461,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { }); } -function getEventData(message: string) { - let [rawType, data] = message.split('\n'); - let type = rawType.trim().split(':')[1].trim(); - if (['index', 'update'].includes(type)) { - return { - type, - data: JSON.parse(data.split('data:')[1].trim()), - }; - } - return; -} - let runnerOptsMgr = new RunnerOptionsManager(); interface RealmContents { From b670f962b3d0d7d11b340ed7b510a02de160251b Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 11 Feb 2025 12:22:32 -0700 Subject: [PATCH 24/39] Revert "Add hackish workaround to remove unstable property" This reverts commit 72b80bdaf9ef93f6b65352514f2da7d6ffa306ed. --- .../realm-indexing-and-querying-test.gts | 69 +++++++------------ 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/packages/host/tests/integration/realm-indexing-and-querying-test.gts b/packages/host/tests/integration/realm-indexing-and-querying-test.gts index ed814e5db4..ff27ba3315 100644 --- a/packages/host/tests/integration/realm-indexing-and-querying-test.gts +++ b/packages/host/tests/integration/realm-indexing-and-querying-test.gts @@ -48,25 +48,6 @@ const testModuleRealm = 'http://localhost:4202/test/'; let loader: Loader; -function stripRealmUserId(card: any) { - let strippedCard = { ...card }; - delete strippedCard?.data?.meta?.realmInfo?.realmUserId; - delete strippedCard?.meta?.realmInfo?.realmUserId; - - if (strippedCard?.included) { - strippedCard.included = strippedCard.included.map((card: any) => { - delete card.meta.realmInfo.realmUserId; - return card; - }); - } - - return strippedCard; -} - -function stripRealmUserIds(cards: any[]) { - return cards.map((card) => stripRealmUserId(card)); -} - module(`Integration | realm indexing and querying`, function (hooks) { setupRenderingTest(hooks); setupBaseRealm(hooks); @@ -110,7 +91,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); let queryEngine = realm.realmIndexQueryEngine; let { data: cards } = await queryEngine.search({}); - assert.deepEqual(stripRealmUserIds(cards), [ + assert.deepEqual(cards, [ { id: `${testRealmURL}empty`, type: 'card', @@ -279,7 +260,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Pet/mango`), ); if (mango?.type === 'doc') { - assert.deepEqual(stripRealmUserId(mango.doc.data), { + assert.deepEqual(mango.doc.data, { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -367,7 +348,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { // we see the "production" version of this card while it is being indexed delete entry.doc.data.meta.lastModified; delete entry.doc.data.meta.resourceCreatedAt; - assert.deepEqual(stripRealmUserId(entry.doc.data), { + assert.deepEqual(entry.doc.data, { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -411,7 +392,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { // we see the "production" version of this card while it is being indexed delete entry.doc.data.meta.lastModified; delete entry.doc.data.meta.resourceCreatedAt; - assert.deepEqual(stripRealmUserId(entry.doc.data), { + assert.deepEqual(entry.doc.data, { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -494,7 +475,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Pet/mango`), ); if (mango?.type === 'doc') { - assert.deepEqual(stripRealmUserId(mango.doc.data), { + assert.deepEqual(mango.doc.data, { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -580,7 +561,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { let indexer = realm.realmIndexQueryEngine; let mango = await indexer.cardDocument(new URL(`${testRealmURL}Pet/mango`)); if (mango?.type === 'doc') { - assert.deepEqual(stripRealmUserId(mango.doc.data), { + assert.deepEqual(mango.doc.data, { id: `${testRealmURL}Pet/mango`, type: 'card', links: { @@ -657,7 +638,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}person-spec`), ); if (entry?.type === 'doc') { - assert.deepEqual(stripRealmUserId(entry.doc.data), { + assert.deepEqual(entry.doc.data, { id: `${testRealmURL}person-spec`, type: 'card', links: { @@ -1621,7 +1602,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (vendor?.type === 'doc') { - assert.deepEqual(stripRealmUserId(vendor.doc), { + assert.deepEqual(vendor.doc, { data: { id: `${testRealmURL}Vendor/vendor1`, type: 'card', @@ -2120,7 +2101,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (hassan?.type === 'doc') { - assert.deepEqual(stripRealmUserId(hassan.doc.data), { + assert.deepEqual(hassan.doc.data, { id: `${testRealmURL}PetPerson/hassan`, type: 'card', links: { self: `${testRealmURL}PetPerson/hassan` }, @@ -2160,7 +2141,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { realmURL: 'http://test-realm/test/', }, }); - assert.deepEqual(stripRealmUserIds(hassan.doc.included), [ + assert.deepEqual(hassan.doc.included, [ { id: `${testRealmURL}Pet/mango`, type: 'card', @@ -2220,7 +2201,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}PetPerson/hassan`), ); if (hassanEntry) { - assert.deepEqual(stripRealmUserId(hassanEntry.searchDoc), { + assert.deepEqual(hassanEntry.searchDoc, { _cardType: 'Pet Person', id: `${testRealmURL}PetPerson/hassan`, firstName: 'Hassan', @@ -2282,7 +2263,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (card?.type === 'doc') { - assert.deepEqual(stripRealmUserId(card.doc), { + assert.deepEqual(card.doc, { data: { id: `${testRealmURL}PetPerson/burcu`, type: 'card', @@ -2325,7 +2306,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}PetPerson/burcu`), ); if (entry) { - assert.deepEqual(stripRealmUserId(entry.searchDoc), { + assert.deepEqual(entry.searchDoc, { _cardType: 'Pet Person', id: `${testRealmURL}PetPerson/burcu`, firstName: 'Burcu', @@ -2399,7 +2380,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); if (spec?.type === 'doc') { - assert.deepEqual(stripRealmUserId(spec.doc.data), { + assert.deepEqual(spec.doc.data, { id: `${testRealmURL}pet-person-spec`, type: 'card', links: { self: `${testRealmURL}pet-person-spec` }, @@ -2552,7 +2533,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Friend/hassan`), ); if (hassan?.type === 'doc') { - assert.deepEqual(stripRealmUserId(hassan.doc.data), { + assert.deepEqual(hassan.doc.data, { id: `${testRealmURL}Friend/hassan`, type: 'card', links: { @@ -2598,7 +2579,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { new URL(`${testRealmURL}Friend/hassan`), ); if (hassanEntry) { - assert.deepEqual(stripRealmUserId(hassanEntry.searchDoc), { + assert.deepEqual(hassanEntry.searchDoc, { _cardType: 'Friend', id: `${testRealmURL}Friend/hassan`, firstName: 'Hassan', @@ -2685,7 +2666,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (hassan?.type === 'doc') { - assert.deepEqual(stripRealmUserId(hassan.doc), { + assert.deepEqual(hassan.doc, { data: { id: `${testRealmURL}Friend/hassan`, type: 'card', @@ -2803,7 +2784,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (mango?.type === 'doc') { - assert.deepEqual(stripRealmUserId(mango.doc), { + assert.deepEqual(mango.doc, { data: { id: `${testRealmURL}Friend/mango`, type: 'card', @@ -2951,7 +2932,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }, ); if (hassan?.type === 'doc') { - assert.deepEqual(stripRealmUserId(hassan.doc), { + assert.deepEqual(hassan.doc, { data: { id: `${testRealmURL}Friend/hassan`, type: 'card', @@ -3075,7 +3056,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (hassan?.type === 'doc') { assert.deepEqual( - stripRealmUserId(hassan.doc.data), + hassan.doc.data, { id: hassanID, type: 'card', @@ -3110,7 +3091,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { ); assert.deepEqual( - stripRealmUserIds(hassan.doc.included), + hassan.doc.included, [ { id: mangoID, @@ -3209,7 +3190,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (mango?.type === 'doc') { assert.deepEqual( - stripRealmUserId(mango.doc.data), + mango.doc.data, { id: mangoID, type: 'card', @@ -3239,7 +3220,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { 'mango doc.data is correct', ); assert.deepEqual( - stripRealmUserIds(mango.doc.included), + mango.doc.included, [ { id: hassanID, @@ -3348,7 +3329,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); if (vanGogh?.type === 'doc') { assert.deepEqual( - stripRealmUserId(vanGogh.doc.data), + vanGogh.doc.data, { id: vanGoghID, type: 'card', @@ -3378,7 +3359,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { 'vanGogh doc.data is correct', ); assert.deepEqual( - stripRealmUserIds(vanGogh.doc.included), + vanGogh.doc.included, [ { id: hassanID, From c3fcda729c2842b44bd65e46f7a826f798c4c042 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 11 Feb 2025 12:54:00 -0700 Subject: [PATCH 25/39] Change to stable way of creating Matrix usernames --- packages/host/tests/helpers/index.gts | 6 ++---- packages/host/tests/integration/realm-test.ts | 3 +++ packages/runtime-common/helpers/const.ts | 11 +++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index cb2d8a0ca1..29acdd2328 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -32,6 +32,7 @@ import { import { testRealmInfo, testRealmURL, + testRealmURLToUsername, } from '@cardstack/runtime-common/helpers/const'; import { Loader } from '@cardstack/runtime-common/loader'; @@ -75,8 +76,6 @@ const { sqlSchema } = ENV; type CardAPI = typeof import('https://cardstack.com/base/card-api'); -let testMatrixCount = 0; - const baseTestMatrix = { url: new URL(`http://localhost:8008`), username: 'test_realm', @@ -576,9 +575,8 @@ async function setupTestRealm({ let iteratedTestMatrix = { ...baseTestMatrix, - username: `@${baseTestMatrix.username}-${testMatrixCount}:localhost`, + username: testRealmURLToUsername(realmURL), }; - testMatrixCount++; realm = new Realm({ url: realmURL, diff --git a/packages/host/tests/integration/realm-test.ts b/packages/host/tests/integration/realm-test.ts index 38ec23a90e..5a83a7e674 100644 --- a/packages/host/tests/integration/realm-test.ts +++ b/packages/host/tests/integration/realm-test.ts @@ -360,6 +360,7 @@ module('Integration | realm', function (hooks) { backgroundURL: 'https://i.postimg.cc/tgRHRV8C/pawel-czerwinski-h-Nrd99q5pe-I-unsplash.jpg', iconURL: 'https://boxel-images.boxel.ai/icons/cardstack.png', + realmUserId: 'test_realm', showAsCatalog: null, visibility: 'public', }, @@ -3080,6 +3081,7 @@ module('Integration | realm', function (hooks) { backgroundURL: 'https://i.postimg.cc/tgRHRV8C/pawel-czerwinski-h-Nrd99q5pe-I-unsplash.jpg', iconURL: 'https://boxel-images.boxel.ai/icons/cardstack.png', + realmUserId: 'test_realm', showAsCatalog: null, visibility: 'public', }, @@ -3255,6 +3257,7 @@ posts/ignore-me.gts name: 'Example Workspace', backgroundURL: 'https://example-background-url.com', iconURL: 'https://example-icon-url.com', + realmUserId: '@realm/test-realm-test:localhost', showAsCatalog: null, visibility: 'public', }, diff --git a/packages/runtime-common/helpers/const.ts b/packages/runtime-common/helpers/const.ts index 54bad34e93..b1e3dd5bb3 100644 --- a/packages/runtime-common/helpers/const.ts +++ b/packages/runtime-common/helpers/const.ts @@ -1,9 +1,20 @@ import { type RealmInfo } from '../index'; export const testRealmURL = `http://test-realm/test/`; + +export function testRealmURLToUsername(realmURLString: string) { + let realmURL = new URL(realmURLString); + let realmUsername = `@realm/${realmURL.host}${realmURL.pathname + .replace('/', '-') + .replace(/\/$/, '')}:localhost`; + + return realmUsername; +} + export const testRealmInfo: RealmInfo = { name: 'Unnamed Workspace', backgroundURL: null, iconURL: null, showAsCatalog: null, visibility: 'public', + realmUserId: testRealmURLToUsername(testRealmURL), }; From d61aefed5a2899b800e3bd8e40fa40ed9167cb13 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 11 Feb 2025 13:21:09 -0700 Subject: [PATCH 26/39] Add missing test setup --- packages/host/tests/integration/realm-test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/host/tests/integration/realm-test.ts b/packages/host/tests/integration/realm-test.ts index 5a83a7e674..434dd09f74 100644 --- a/packages/host/tests/integration/realm-test.ts +++ b/packages/host/tests/integration/realm-test.ts @@ -36,6 +36,7 @@ import { StringField, field, } from '../helpers/base-realm'; +import { setupMockMatrix } from '../helpers/mock-matrix'; import { setupRenderingTest } from '../helpers/setup'; import '@cardstack/runtime-common/helpers/code-equality-assertion'; @@ -50,6 +51,8 @@ module('Integration | realm', function (hooks) { loader = lookupLoaderService().loader; }); + // FIXME maybe this needs to happen in every test now? And setupServerSentEvents is obsolete + setupMockMatrix(hooks); setupServerSentEvents(hooks); setupLocalIndexing(hooks); setupCardLogs( From 0c9d239e4130c4c1078d5445babe6fc74bd1a7e4 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 11 Feb 2025 16:28:36 -0700 Subject: [PATCH 27/39] Add early return when Matrix not logged in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This might need refinement…? --- packages/realm-server/node-realm.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index 29f4fc9a6f..5c889730d5 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -189,6 +189,13 @@ export class NodeAdapter implements RealmAdapter { event: ServerEvents, matrixClient: MatrixClient, ): Promise { + console.log('sending server event', event); + + if (!matrixClient.isLoggedIn()) { + console.log('not logged in, skipping server event'); + return; + } + let dmRooms = (await matrixClient.getAccountData>( 'boxel.session-rooms', From 88164a50aa2b8369301659e76854a691a4eb7fe0 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 11 Feb 2025 16:28:56 -0700 Subject: [PATCH 28/39] Fix room specification for Matrix/SSE --- packages/realm-server/node-realm.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index 5c889730d5..f61845cd85 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -201,7 +201,8 @@ export class NodeAdapter implements RealmAdapter { 'boxel.session-rooms', )) ?? {}; - for (let roomId of Object.keys(dmRooms)) { + for (let userId of Object.keys(dmRooms)) { + let roomId = dmRooms[userId]; try { await matrixClient.sendEvent(roomId, 'm.room.message', { body: JSON.stringify({ @@ -212,7 +213,11 @@ export class NodeAdapter implements RealmAdapter { format: 'app.boxel.sse-format', }); } catch (e) { - console.log(`Unable to send event in room ${roomId}`, event, e); + console.log( + `Unable to send event in room ${roomId} for user ${userId}`, + event, + e, + ); } } } From eaa9eb356fa09d03485a37f3036650472e3fc6e6 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 12 Feb 2025 12:16:20 -0700 Subject: [PATCH 29/39] Add guard against missing Matrix --- packages/realm-server/node-realm.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/realm-server/node-realm.ts b/packages/realm-server/node-realm.ts index f61845cd85..cbeff9bdbb 100644 --- a/packages/realm-server/node-realm.ts +++ b/packages/realm-server/node-realm.ts @@ -196,10 +196,18 @@ export class NodeAdapter implements RealmAdapter { return; } - let dmRooms = - (await matrixClient.getAccountData>( - 'boxel.session-rooms', - )) ?? {}; + let dmRooms; + + try { + dmRooms = + (await matrixClient.getAccountData>( + 'boxel.session-rooms', + )) ?? {}; + } catch (e) { + // FIXME this is happening in CI, Matrix has been shut down presumably + console.log('error getting account data', e); + return; + } for (let userId of Object.keys(dmRooms)) { let roomId = dmRooms[userId]; From 84c1a1d5aaed45343221736b4d33ea1dbc0327c2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 12 Feb 2025 15:21:18 -0700 Subject: [PATCH 30/39] Fix some type errors --- packages/host/app/services/matrix-service.ts | 3 ++- packages/host/app/services/message-service.ts | 2 ++ packages/host/tests/helpers/adapter.ts | 2 +- packages/host/tests/helpers/index.gts | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/host/app/services/matrix-service.ts b/packages/host/app/services/matrix-service.ts index 9bc74443bc..b9b3e1df11 100644 --- a/packages/host/app/services/matrix-service.ts +++ b/packages/host/app/services/matrix-service.ts @@ -1317,7 +1317,8 @@ export default class MatrixService extends Service { await this.realmServer.handleEvent(event); } else if ( event.type === 'm.room.message' && - event.content?.msgtype === 'app.boxel.sse' + event.content?.msgtype === 'app.boxel.sse' && + event.sender ) { // FIXME provenance should be checked console.log('received sse event', event); diff --git a/packages/host/app/services/message-service.ts b/packages/host/app/services/message-service.ts index 17b148aabf..7a333a3579 100644 --- a/packages/host/app/services/message-service.ts +++ b/packages/host/app/services/message-service.ts @@ -8,6 +8,8 @@ import window from 'ember-window-mock'; import qs from 'qs'; +import type { ServerEvents } from '@cardstack/runtime-common/realm'; + import { SessionLocalStorageKey } from '../utils/local-storage-keys'; import type NetworkService from './network'; diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index ccf1cf7e1a..788827846d 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -102,7 +102,7 @@ export class TestRealmAdapter implements RealmAdapter { return; } - let mockLoader = this.owner.lookup('service:matrix-mock-utils'); + let mockLoader = this.owner.lookup('service:matrix-mock-utils') as any; if (!mockLoader) { console.log('mockLoader not found, skipping'); diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 29acdd2328..ad12bedf7b 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -8,7 +8,7 @@ import { import { findAll, waitUntil, waitFor, click } from '@ember/test-helpers'; import GlimmerComponent from '@glimmer/component'; -import { MatrixEvent } from 'matrix-js-sdk'; +import { IEvent } from 'matrix-js-sdk'; import ms from 'ms'; import { @@ -329,7 +329,7 @@ export function setupServerSentEvents(hooks: NestedHooks) { }); } - let roomEvents: MatrixEvent[] = []; + let roomEvents: IEvent[] = []; let timeout = setTimeout( () => From 42559747d751a80f89eff474dea4095957fd77a9 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 12 Feb 2025 15:28:11 -0700 Subject: [PATCH 31/39] Remove remnants of old approach --- packages/host/tests/acceptance/code-submode/editor-test.ts | 1 - .../host/tests/acceptance/code-submode/schema-editor-test.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/host/tests/acceptance/code-submode/editor-test.ts b/packages/host/tests/acceptance/code-submode/editor-test.ts index ad0b266039..db828f0907 100644 --- a/packages/host/tests/acceptance/code-submode/editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/editor-test.ts @@ -270,7 +270,6 @@ module('Acceptance | code submode | editor tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', - realmUserId: '@test_realm:localhost', }, 'Person/john-with-bad-pet-link.json': { data: { diff --git a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts index cbe4bf783d..5a84c7fdda 100644 --- a/packages/host/tests/acceptance/code-submode/schema-editor-test.ts +++ b/packages/host/tests/acceptance/code-submode/schema-editor-test.ts @@ -331,7 +331,6 @@ module('Acceptance | code submode | schema editor tests', function (hooks) { backgroundURL: 'https://i.postimg.cc/VNvHH93M/pawel-czerwinski-Ly-ZLa-A5jti-Y-unsplash.jpg', iconURL: 'https://i.postimg.cc/L8yXRvws/icon.png', - realmUserId: '@test_realm:localhost', }, }, })); From f38e87125cdd6e957eb238a67ee46d69ce110fe9 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 15:58:47 -0700 Subject: [PATCH 32/39] Fix how rooms are chosen for relaying It was sending SSE messages in AI assistant rooms. --- packages/host/tests/helpers/adapter.ts | 20 ++++++++++------- packages/host/tests/helpers/index.gts | 30 +++++++++++++++----------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/host/tests/helpers/adapter.ts b/packages/host/tests/helpers/adapter.ts index 788827846d..16c21885dd 100644 --- a/packages/host/tests/helpers/adapter.ts +++ b/packages/host/tests/helpers/adapter.ts @@ -115,15 +115,19 @@ export class TestRealmAdapter implements RealmAdapter { let realmMatrixUsername = matrixClient.username; + console.log('room ids', getRoomIds()); + for (let roomId of getRoomIds()) { - simulateRemoteMessage(roomId, realmMatrixUsername, { - msgtype: 'app.boxel.sse', // FIXME extract/constant - format: 'app.boxel.sse-format', // FIXME does this matter? - body: JSON.stringify({ - type: event.type, - data: event.data, - }), - }); + if (roomId.startsWith('session-room-for-')) { + simulateRemoteMessage(roomId, realmMatrixUsername, { + msgtype: 'app.boxel.sse', // FIXME extract/constant + format: 'app.boxel.sse-format', // FIXME does this matter? + body: JSON.stringify({ + type: event.type, + data: event.data, + }), + }); + } } } diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index ad12bedf7b..30147e0dc8 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -316,19 +316,6 @@ export function setupServerSentEvents(hooks: NestedHooks) { let mockLoader = this.owner.lookup('service:matrix-mock-utils') as any; let mockMatrixUtils = (await mockLoader.load()) as MockUtils; - // FIXME shouldn’t the room be created elsewhere? and how should the username be known? - let realmSessionRoomId = `session-room-for-testuser`; - - let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; - - if (!getRoomIds().includes(realmSessionRoomId)) { - createAndJoinRoom({ - sender: realm.matrixUsername, - name: realmSessionRoomId, - id: realmSessionRoomId, - }); - } - let roomEvents: IEvent[] = []; let timeout = setTimeout( @@ -587,6 +574,23 @@ async function setupTestRealm({ dbAdapter, queue, }); + + let mockLoader = owner.lookup('service:matrix-mock-utils') as any; + let mockMatrixUtils = (await mockLoader.load()) as MockUtils; + + // FIXME how should the username be known? + let realmSessionRoomId = `session-room-for-testuser`; + + let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; + + if (!getRoomIds().includes(realmSessionRoomId)) { + createAndJoinRoom({ + sender: realm.matrixUsername, + name: realmSessionRoomId, + id: realmSessionRoomId, + }); + } + // TODO this is the only use of Realm.maybeHandle left--can we get rid of it? virtualNetwork.mount(realm.maybeHandle); await adapter.ready; From 78c9113feaedc4891f1d50ac1a88014786fd0687 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 16:19:12 -0700 Subject: [PATCH 33/39] Add mistakenly-removed line --- packages/host/tests/helpers/index.gts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 30147e0dc8..67d0ac1ce0 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -337,6 +337,9 @@ export function setupServerSentEvents(hooks: NestedHooks) { ); } + // FIXME how should the username be known? … duplicated from setupTestRealm + let realmSessionRoomId = `session-room-for-testuser`; + roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); let sseRoomEvents = roomEvents.filter( (e) => e.content?.msgtype === 'app.boxel.sse', From bc39719e7d7bacb28dcbecfbcd983f45dc57cc5d Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 16:36:29 -0700 Subject: [PATCH 34/39] Add missing setup I hate it --- packages/host/tests/integration/card-prerender-test.gts | 2 ++ .../commands/add-field-to-card-definition-command-test.gts | 2 ++ .../host/tests/integration/commands/switch-submode-test.gts | 2 ++ .../host/tests/integration/commands/write-text-file-test.gts | 2 ++ packages/host/tests/integration/components/card-api-test.gts | 2 ++ packages/host/tests/integration/components/computed-test.gts | 2 ++ .../integration/components/prerendered-card-search-test.gts | 2 ++ .../host/tests/integration/components/serialization-test.gts | 2 ++ .../tests/integration/components/text-input-validator-test.gts | 2 ++ .../host/tests/integration/components/text-suggestion-test.gts | 2 ++ .../tests/integration/realm-indexing-and-querying-test.gts | 3 +++ packages/host/tests/integration/resources/search-test.ts | 2 ++ 12 files changed, 25 insertions(+) diff --git a/packages/host/tests/integration/card-prerender-test.gts b/packages/host/tests/integration/card-prerender-test.gts index f0bcd407bd..83787149a3 100644 --- a/packages/host/tests/integration/card-prerender-test.gts +++ b/packages/host/tests/integration/card-prerender-test.gts @@ -7,6 +7,7 @@ import stripScopedCSSAttributes from '@cardstack/runtime-common/helpers/strip-sc import { Loader } from '@cardstack/runtime-common/loader'; import { Realm } from '@cardstack/runtime-common/realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { testRealmURL, setupCardLogs, @@ -29,6 +30,7 @@ module('Integration | card-prerender', function (hooks) { }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupCardLogs( hooks, async () => await loader.import(`${baseRealm.url}card-api`), diff --git a/packages/host/tests/integration/commands/add-field-to-card-definition-command-test.gts b/packages/host/tests/integration/commands/add-field-to-card-definition-command-test.gts index e78abe9907..e9bad6a7a6 100644 --- a/packages/host/tests/integration/commands/add-field-to-card-definition-command-test.gts +++ b/packages/host/tests/integration/commands/add-field-to-card-definition-command-test.gts @@ -19,6 +19,7 @@ import { testRealmURL, testRealmInfo, } from '../../helpers'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; let loader: Loader; @@ -37,6 +38,7 @@ module( function (hooks) { setupRenderingTest(hooks); setupLocalIndexing(hooks); + setupMockMatrix(hooks); hooks.beforeEach(function (this: RenderingTestContext) { getOwner(this)!.register('service:realm', StubRealmService); diff --git a/packages/host/tests/integration/commands/switch-submode-test.gts b/packages/host/tests/integration/commands/switch-submode-test.gts index 09dc489c16..491ee3426b 100644 --- a/packages/host/tests/integration/commands/switch-submode-test.gts +++ b/packages/host/tests/integration/commands/switch-submode-test.gts @@ -19,6 +19,7 @@ import { testRealmURL, testRealmInfo, } from '../../helpers'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; let loader: Loader; @@ -35,6 +36,7 @@ class StubRealmService extends RealmService { module('Integration | commands | switch-submode', function (hooks) { setupRenderingTest(hooks); setupLocalIndexing(hooks); + setupMockMatrix(hooks); hooks.beforeEach(function (this: RenderingTestContext) { getOwner(this)!.register('service:realm', StubRealmService); diff --git a/packages/host/tests/integration/commands/write-text-file-test.gts b/packages/host/tests/integration/commands/write-text-file-test.gts index df14b2597b..3e2ac56685 100644 --- a/packages/host/tests/integration/commands/write-text-file-test.gts +++ b/packages/host/tests/integration/commands/write-text-file-test.gts @@ -20,6 +20,7 @@ import { testRealmURL, testRealmInfo, } from '../../helpers'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; let loader: Loader; @@ -37,6 +38,7 @@ class StubRealmService extends RealmService { module('Integration | commands | write-text-file', function (hooks) { setupRenderingTest(hooks); setupLocalIndexing(hooks); + setupMockMatrix(hooks); hooks.beforeEach(function (this: RenderingTestContext) { getOwner(this)!.register('service:realm', StubRealmService); diff --git a/packages/host/tests/integration/components/card-api-test.gts b/packages/host/tests/integration/components/card-api-test.gts index 3b2c9024e1..6cccc6e3b0 100644 --- a/packages/host/tests/integration/components/card-api-test.gts +++ b/packages/host/tests/integration/components/card-api-test.gts @@ -33,6 +33,7 @@ import { Component, // realmURL, } from '../../helpers/base-realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { renderComponent } from '../../helpers/render-component'; import { setupRenderingTest } from '../../helpers/setup'; @@ -87,6 +88,7 @@ module('Integration | card api (Usage of publicAPI actions)', function (hooks) { }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupServerSentEvents(hooks); setupBaseRealm(hooks); diff --git a/packages/host/tests/integration/components/computed-test.gts b/packages/host/tests/integration/components/computed-test.gts index 93a475592e..d3c3f77134 100644 --- a/packages/host/tests/integration/components/computed-test.gts +++ b/packages/host/tests/integration/components/computed-test.gts @@ -32,6 +32,7 @@ import { linksTo, linksToMany, } from '../../helpers/base-realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { renderCard } from '../../helpers/render-component'; import { setupRenderingTest } from '../../helpers/setup'; @@ -39,6 +40,7 @@ let loader: Loader; module('Integration | computeds', function (hooks) { setupRenderingTest(hooks); + setupMockMatrix(hooks); setupBaseRealm(hooks); hooks.beforeEach(function (this: RenderingTestContext) { diff --git a/packages/host/tests/integration/components/prerendered-card-search-test.gts b/packages/host/tests/integration/components/prerendered-card-search-test.gts index 45a017381e..a55731a013 100644 --- a/packages/host/tests/integration/components/prerendered-card-search-test.gts +++ b/packages/host/tests/integration/components/prerendered-card-search-test.gts @@ -42,6 +42,7 @@ import { linksTo, setupBaseRealm, } from '../../helpers/base-realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; module(`Integration | prerendered-card-search`, function (hooks) { @@ -56,6 +57,7 @@ module(`Integration | prerendered-card-search`, function (hooks) { }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupServerSentEvents(hooks); setupBaseRealm(hooks); hooks.beforeEach(async function (this: RenderingTestContext) { diff --git a/packages/host/tests/integration/components/serialization-test.gts b/packages/host/tests/integration/components/serialization-test.gts index 0f1a7769e7..c64fa2a7f6 100644 --- a/packages/host/tests/integration/components/serialization-test.gts +++ b/packages/host/tests/integration/components/serialization-test.gts @@ -57,6 +57,7 @@ import { EthereumAddressField, } from '../../helpers/base-realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { renderCard } from '../../helpers/render-component'; import { setupRenderingTest } from '../../helpers/setup'; @@ -77,6 +78,7 @@ module('Integration | serialization', function (hooks) { loader = lookupLoaderService().loader; }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupCardLogs( hooks, async () => await loader.import(`${baseRealm.url}card-api`), diff --git a/packages/host/tests/integration/components/text-input-validator-test.gts b/packages/host/tests/integration/components/text-input-validator-test.gts index dcf728c3a3..626b8b9d5a 100644 --- a/packages/host/tests/integration/components/text-input-validator-test.gts +++ b/packages/host/tests/integration/components/text-input-validator-test.gts @@ -36,6 +36,7 @@ import { provideConsumeContext, lookupLoaderService, } from '../../helpers'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { renderComponent } from '../../helpers/render-component'; import { setupRenderingTest } from '../../helpers/setup'; @@ -47,6 +48,7 @@ module('Integration | text-input-validator', function (hooks) { let realm: Realm; setupRenderingTest(hooks); setupLocalIndexing(hooks); + setupMockMatrix(hooks); async function loadCard(url: string): Promise { let { createFromSerialized, recompute } = cardApi; diff --git a/packages/host/tests/integration/components/text-suggestion-test.gts b/packages/host/tests/integration/components/text-suggestion-test.gts index b0670693b2..57062a61a4 100644 --- a/packages/host/tests/integration/components/text-suggestion-test.gts +++ b/packages/host/tests/integration/components/text-suggestion-test.gts @@ -15,6 +15,7 @@ import { setupLocalIndexing, lookupLoaderService, } from '../../helpers'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; let cardApi: typeof import('https://cardstack.com/base/card-api'); @@ -24,6 +25,7 @@ let loader: Loader; module('Integration | text-suggestion | card-chooser-title', function (hooks) { setupRenderingTest(hooks); setupLocalIndexing(hooks); + setupMockMatrix(hooks); hooks.beforeEach(function (this: RenderingTestContext) { loader = lookupLoaderService().loader; diff --git a/packages/host/tests/integration/realm-indexing-and-querying-test.gts b/packages/host/tests/integration/realm-indexing-and-querying-test.gts index ff27ba3315..73fbaefae7 100644 --- a/packages/host/tests/integration/realm-indexing-and-querying-test.gts +++ b/packages/host/tests/integration/realm-indexing-and-querying-test.gts @@ -18,6 +18,8 @@ import { RealmPaths } from '@cardstack/runtime-common/paths'; import { RealmIndexQueryEngine } from '@cardstack/runtime-common/realm-index-query-engine'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; + import { testRealmURL, testRealmInfo, @@ -57,6 +59,7 @@ module(`Integration | realm indexing and querying`, function (hooks) { }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupCardLogs( hooks, async () => await loader.import(`${baseRealm.url}card-api`), diff --git a/packages/host/tests/integration/resources/search-test.ts b/packages/host/tests/integration/resources/search-test.ts index a08197dae3..264523498d 100644 --- a/packages/host/tests/integration/resources/search-test.ts +++ b/packages/host/tests/integration/resources/search-test.ts @@ -27,6 +27,7 @@ import { type TestContextWithSSE, } from '../../helpers'; import { setupBaseRealm } from '../../helpers/base-realm'; +import { setupMockMatrix } from '../../helpers/mock-matrix'; import { setupRenderingTest } from '../../helpers/setup'; class StubRealmService extends RealmService { @@ -50,6 +51,7 @@ module(`Integration | search resource`, function (hooks) { }); setupLocalIndexing(hooks); + setupMockMatrix(hooks); setupServerSentEvents(hooks); setupBaseRealm(hooks); hooks.beforeEach(async function (this: RenderingTestContext) { From c75b34511068b8f1b7241f0a3a63ec67e6d3620f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 17:13:28 -0700 Subject: [PATCH 35/39] Fix relative paths ugh --- packages/host/tests/integration/card-prerender-test.gts | 2 +- .../tests/integration/realm-indexing-and-querying-test.gts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/host/tests/integration/card-prerender-test.gts b/packages/host/tests/integration/card-prerender-test.gts index 83787149a3..f034771d33 100644 --- a/packages/host/tests/integration/card-prerender-test.gts +++ b/packages/host/tests/integration/card-prerender-test.gts @@ -7,7 +7,6 @@ import stripScopedCSSAttributes from '@cardstack/runtime-common/helpers/strip-sc import { Loader } from '@cardstack/runtime-common/loader'; import { Realm } from '@cardstack/runtime-common/realm'; -import { setupMockMatrix } from '../../helpers/mock-matrix'; import { testRealmURL, setupCardLogs, @@ -16,6 +15,7 @@ import { setupIntegrationTestRealm, lookupLoaderService, } from '../helpers'; +import { setupMockMatrix } from '../helpers/mock-matrix'; import { setupRenderingTest } from '../helpers/setup'; let loader: Loader; diff --git a/packages/host/tests/integration/realm-indexing-and-querying-test.gts b/packages/host/tests/integration/realm-indexing-and-querying-test.gts index 73fbaefae7..88c49cc289 100644 --- a/packages/host/tests/integration/realm-indexing-and-querying-test.gts +++ b/packages/host/tests/integration/realm-indexing-and-querying-test.gts @@ -18,8 +18,6 @@ import { RealmPaths } from '@cardstack/runtime-common/paths'; import { RealmIndexQueryEngine } from '@cardstack/runtime-common/realm-index-query-engine'; -import { setupMockMatrix } from '../../helpers/mock-matrix'; - import { testRealmURL, testRealmInfo, @@ -43,6 +41,7 @@ import { setupBaseRealm, StringField, } from '../helpers/base-realm'; +import { setupMockMatrix } from '../helpers/mock-matrix'; import { setupRenderingTest } from '../helpers/setup'; const paths = new RealmPaths(new URL(testRealmURL)); From dacbc69aeea61570468a897259553d142fdebe19 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 19:02:25 -0700 Subject: [PATCH 36/39] Fix filtering of expected events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This doesn’t quite work…? At least for the copy card test --- packages/host/tests/helpers/index.gts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index 67d0ac1ce0..c7f9c236db 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -342,7 +342,9 @@ export function setupServerSentEvents(hooks: NestedHooks) { roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); let sseRoomEvents = roomEvents.filter( - (e) => e.content?.msgtype === 'app.boxel.sse', + (e) => + e.content?.msgtype === 'app.boxel.sse' && + e.sender === realm.matrixUsername, ); if (expectedEvents) { From 5a8617a8a6b95a09412e5627fd93bdf23bcd1aaa Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 19:06:27 -0700 Subject: [PATCH 37/39] Change constructed room name --- packages/host/tests/helpers/index.gts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/host/tests/helpers/index.gts b/packages/host/tests/helpers/index.gts index c7f9c236db..1ea515160f 100644 --- a/packages/host/tests/helpers/index.gts +++ b/packages/host/tests/helpers/index.gts @@ -337,10 +337,11 @@ export function setupServerSentEvents(hooks: NestedHooks) { ); } - // FIXME how should the username be known? … duplicated from setupTestRealm - let realmSessionRoomId = `session-room-for-testuser`; + // FIXME duplicated from setupTestRealm, also this is the user’s username elsewher, not the realm’s username + let realmSessionRoomId = `session-room-for-${realm.matrixUsername}`; roomEvents = mockMatrixUtils.getRoomEvents(realmSessionRoomId); + let sseRoomEvents = roomEvents.filter( (e) => e.content?.msgtype === 'app.boxel.sse' && @@ -583,8 +584,7 @@ async function setupTestRealm({ let mockLoader = owner.lookup('service:matrix-mock-utils') as any; let mockMatrixUtils = (await mockLoader.load()) as MockUtils; - // FIXME how should the username be known? - let realmSessionRoomId = `session-room-for-testuser`; + let realmSessionRoomId = `session-room-for-${realm.matrixUsername}`; let { createAndJoinRoom, getRoomIds } = mockMatrixUtils; From cd623195e4e16b1fee789234f3354cb6e4c8cc47 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 19:24:13 -0700 Subject: [PATCH 38/39] Fix type error --- packages/host/app/services/message-service.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/host/app/services/message-service.ts b/packages/host/app/services/message-service.ts index 7a333a3579..562d2d3e43 100644 --- a/packages/host/app/services/message-service.ts +++ b/packages/host/app/services/message-service.ts @@ -8,15 +8,13 @@ import window from 'ember-window-mock'; import qs from 'qs'; -import type { ServerEvents } from '@cardstack/runtime-common/realm'; - import { SessionLocalStorageKey } from '../utils/local-storage-keys'; import type NetworkService from './network'; export default class MessageService extends Service { @tracked subscriptions: Map = new Map(); - @tracked listenerCallbacks: Map void)[]> = + @tracked listenerCallbacks: Map void)[]> = new Map(); @service private declare network: NetworkService; @@ -74,7 +72,7 @@ export default class MessageService extends Service { let eventWithStringData = { type: event.type, data: JSON.stringify(event.data), - }; + } as MessageEvent; cb(eventWithStringData); }); } From 2ff637117fa25ce1e26866245c9c7016e0e7cb46 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 13 Feb 2025 20:05:43 -0700 Subject: [PATCH 39/39] Add missing property Will this cascade? --- packages/realm-server/tests/helpers/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/realm-server/tests/helpers/index.ts b/packages/realm-server/tests/helpers/index.ts index 1f285ca90d..6026836c7a 100644 --- a/packages/realm-server/tests/helpers/index.ts +++ b/packages/realm-server/tests/helpers/index.ts @@ -55,6 +55,7 @@ export const testRealmInfo = { iconURL: null, showAsCatalog: null, visibility: 'public', + realmUserId: testMatrix.username, }; export const realmServerTestMatrix: MatrixConfig = {