2022-02-22 15:06:29 -07:00
'use strict' ;
2022-02-23 20:25:05 -07:00
process . env . NODE _ENV = 'test' ;
2022-02-22 15:06:29 -07:00
const assert = require ( 'assert' ) ;
2022-02-22 19:25:24 -07:00
const urlJoin = require ( 'url-join' ) ;
2022-02-24 02:27:53 -07:00
const escapeStringRegexp = require ( 'escape-string-regexp' ) ;
2022-02-22 19:25:24 -07:00
const { MatrixAuth } = require ( 'matrix-bot-sdk' ) ;
2022-02-24 02:27:53 -07:00
const { parseHTML } = require ( 'linkedom' ) ;
2022-02-22 19:25:24 -07:00
2022-02-23 20:25:05 -07:00
const { fetchEndpointAsText , fetchEndpointAsJson } = require ( '../server/lib/fetch-endpoint' ) ;
const MatrixPublicArchiveURLCreator = require ( 'matrix-public-archive-shared/lib/url-creator' ) ;
const config = require ( '../server/lib/config' ) ;
const testMatrixServerUrl1 = config . get ( 'testMatrixServerUrl1' ) ;
const testMatrixServerUrl2 = config . get ( 'testMatrixServerUrl2' ) ;
assert ( testMatrixServerUrl1 ) ;
assert ( testMatrixServerUrl2 ) ;
2022-02-24 02:27:53 -07:00
const basePath = config . get ( 'basePath' ) ;
2022-02-23 20:25:05 -07:00
assert ( basePath ) ;
2022-02-24 02:27:53 -07:00
const interactive = config . get ( 'interactive' ) ;
2022-02-23 20:25:05 -07:00
const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator ( basePath ) ;
2022-02-22 15:06:29 -07:00
2022-02-23 20:25:05 -07:00
const HOMESERVER _URL _TO _PRETTY _NAME _MAP = {
[ testMatrixServerUrl1 ] : 'hs1' ,
[ testMatrixServerUrl2 ] : 'hs2' ,
} ;
2022-02-22 19:25:24 -07:00
async function getTestClientForHs ( testMatrixServerUrl ) {
const auth = new MatrixAuth ( testMatrixServerUrl ) ;
const client = await auth . passwordRegister (
2022-02-23 20:25:05 -07:00
` user-t ${ new Date ( ) . getTime ( ) } -r ${ Math . floor ( Math . random ( ) * 1000000000 ) } ` ,
2022-02-22 19:25:24 -07:00
'password'
) ;
return client ;
}
2022-02-22 19:55:42 -07:00
async function createMessagesInRoom ( client , roomId , numMessages , prefix ) {
2022-02-22 19:25:24 -07:00
let eventIds = [ ] ;
2022-02-22 19:55:42 -07:00
for ( let i = 0 ; i < numMessages ; i ++ ) {
2022-02-22 19:25:24 -07:00
const eventId = await client . sendMessage ( roomId , {
msgtype : 'm.text' ,
2022-02-22 19:55:42 -07:00
body : ` ${ prefix } - message ${ i } ` ,
2022-02-22 19:25:24 -07:00
} ) ;
eventIds . push ( eventId ) ;
}
2022-02-22 19:55:42 -07:00
return eventIds ;
}
async function createTestRoom ( client ) {
const roomId = await client . createRoom ( {
preset : 'public_chat' ,
name : 'the hangout spot' ,
2022-02-23 20:25:05 -07:00
initial _state : [
{
type : 'm.room.history_visibility' ,
state _key : '' ,
content : {
history _visibility : 'world_readable' ,
} ,
} ,
] ,
2022-02-22 19:55:42 -07:00
} ) ;
return roomId ;
2022-02-22 19:25:24 -07:00
}
2022-02-22 15:06:29 -07:00
describe ( 'matrix-public-archive' , ( ) => {
2022-02-24 02:27:53 -07:00
let server ;
before ( ( ) => {
// Start the archive server
server = require ( '../server/server' ) ;
} ) ;
2022-02-23 20:25:05 -07:00
after ( ( ) => {
2022-02-24 02:27:53 -07:00
if ( ! interactive ) {
server . close ( ) ;
}
2022-02-23 20:25:05 -07:00
} ) ;
2022-02-24 02:27:53 -07:00
// Sanity check that our test homeservers can actually federate with each
// other. The rest of the tests won't work properly if this isn't working.
2022-02-22 19:55:42 -07:00
it ( 'Test federation between fixture homeservers' , async ( ) => {
2022-02-23 20:25:05 -07:00
try {
const hs1Client = await getTestClientForHs ( testMatrixServerUrl1 ) ;
const hs2Client = await getTestClientForHs ( testMatrixServerUrl2 ) ;
// Create a room on hs2
const hs2RoomId = await createTestRoom ( hs2Client ) ;
const room2EventIds = await createMessagesInRoom (
hs2Client ,
hs2RoomId ,
10 ,
HOMESERVER _URL _TO _PRETTY _NAME _MAP [ hs2Client . homeserverUrl ]
) ;
2022-02-22 19:55:42 -07:00
2022-02-23 20:25:05 -07:00
// Join hs1 to a room on hs2 (federation)
await hs1Client . joinRoom ( hs2RoomId , 'hs2' ) ;
2022-02-22 19:55:42 -07:00
2022-02-23 20:25:05 -07:00
// From, hs1, make sure we can fetch messages from hs2
const messagesEndpoint = urlJoin (
hs1Client . homeserverUrl ,
` _matrix/client/r0/rooms/ ${ hs2RoomId } /messages?limit=5&dir=b&filter={"types":["m.room.message"]} `
) ;
const messageResData = await fetchEndpointAsJson ( messagesEndpoint , {
accessToken : hs1Client . accessToken ,
2022-02-22 19:55:42 -07:00
} ) ;
2022-02-23 20:25:05 -07:00
// Make sure it returned some messages
assert . strictEqual ( messageResData . chunk . length , 5 ) ;
// Make sure all of the messages belong to the room
messageResData . chunk . map ( ( event ) => {
const isEventInRoomFromHs2 = room2EventIds . some ( ( room2EventId ) => {
return room2EventId === event . event _id ;
} ) ;
// Make sure the message belongs to the room on hs2
assert . strictEqual (
isEventInRoomFromHs2 ,
true ,
` Expected ${ event . event _id } ( ${ event . type } : " ${
event . content . body
} " ) to be in room on hs2 = $ { JSON . stringify ( room2EventIds ) } `
) ;
} ) ;
} catch ( err ) {
if ( err . body ) {
// FIXME: Remove this try/catch once the matrix-bot-sdk no longer throws
// huge response objects as errors, see
// https://github.com/turt2live/matrix-bot-sdk/pull/158
throw new Error (
` Error occured in matrix-bot-sdk (this new error is to stop it from logging the huge response) statusCode= ${
err . statusCode
} body = $ { JSON . stringify ( err . body ) } `
) ;
}
throw err ;
}
2022-02-22 15:06:29 -07:00
} ) ;
2022-02-22 19:55:42 -07:00
2022-02-24 12:06:19 -07:00
it ( 'shows all events in a given day' , async ( ) => {
try {
const client = await getTestClientForHs ( testMatrixServerUrl1 ) ;
const roomId = await createTestRoom ( client ) ;
const archiveUrl = matrixPublicArchiveURLCreator . archiveUrlForDate ( roomId , new Date ( ) ) ;
// Just render the page initially so that the archiver user is already joined to the page.
// We don't want their join event masking the one-off problem where we're missing the latest message in the room.
await fetchEndpointAsText ( archiveUrl ) ;
const messageTextList = [
` Amontons' First Law: The force of friction is directly proportional to the applied load. ` ,
` Amontons' Second Law: The force of friction is independent of the apparent area of contact. ` ,
// We're aiming for this to be the last message in the room
` Coulomb's Law of Friction: Kinetic friction is independent of the sliding velocity. ` ,
] ;
const eventIds = [ ] ;
for ( const messageText of messageTextList ) {
const eventId = await client . sendMessage ( roomId , {
msgtype : 'm.text' ,
body : messageText ,
} ) ;
eventIds . push ( eventId ) ;
}
// Sanity check that we actually sent some messages
assert . strictEqual ( eventIds . length , 3 ) ;
if ( interactive ) {
console . log ( 'Interactive URL for test' , archiveUrl ) ;
}
const archivePageHtml = await fetchEndpointAsText ( archiveUrl ) ;
const dom = parseHTML ( archivePageHtml ) ;
// Make sure the messages are visible
for ( let i = 0 ; i < eventIds . length ; i ++ ) {
const eventId = eventIds [ i ] ;
const eventText = messageTextList [ i ] ;
assert . match (
dom . document . querySelector ( ` [data-event-id=" ${ eventId } "] ` ) . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( eventText ) } .* ` )
) ;
}
} catch ( err ) {
if ( err . body ) {
// FIXME: Remove this try/catch once the matrix-bot-sdk no longer throws
// huge response objects as errors, see
// https://github.com/turt2live/matrix-bot-sdk/pull/158
throw new Error (
` Error occured in matrix-bot-sdk (this new error is to stop it from logging the huge response) statusCode= ${
err . statusCode
} body = $ { JSON . stringify ( err . body ) } `
) ;
}
throw err ;
}
} ) ;
2022-02-24 02:27:53 -07:00
// eslint-disable-next-line max-statements
2022-02-23 20:25:05 -07:00
it ( 'can render diverse messages' , async ( ) => {
try {
const client = await getTestClientForHs ( testMatrixServerUrl1 ) ;
const roomId = await createTestRoom ( client ) ;
// TODO: Set avatar of user
// TODO: Set avatar of room
// Test image
const mxcUri = await client . uploadContentFromUrl (
'https://en.wikipedia.org/wiki/Friction#/media/File:Friction_between_surfaces.jpg'
) ;
2022-02-24 02:27:53 -07:00
const imageEventId = await client . sendMessage ( roomId , {
2022-02-23 20:25:05 -07:00
body : 'Friction_between_surfaces.jpeg' ,
info : {
size : 396644 ,
mimetype : 'image/jpeg' ,
2022-02-24 02:27:53 -07:00
thumbnail _info : {
w : 800 ,
h : 390 ,
mimetype : 'image/jpeg' ,
size : 126496 ,
} ,
2022-02-23 20:25:05 -07:00
w : 1894 ,
h : 925 ,
'xyz.amorgan.blurhash' : 'LkR3G|IU?w%NbwbIemae_NxuD$M{' ,
2022-02-24 02:27:53 -07:00
// TODO: How to get a proper thumnail URL that will load?
thumbnail _url : mxcUri ,
2022-02-23 20:25:05 -07:00
} ,
msgtype : 'm.image' ,
url : mxcUri ,
} ) ;
// A normal text message
2022-02-24 02:27:53 -07:00
const normalMessageText1 =
'^ Figure 1: Simulated blocks with fractal rough surfaces, exhibiting static frictional interactions' ;
const normalMessageEventId1 = await client . sendMessage ( roomId , {
2022-02-23 20:25:05 -07:00
msgtype : 'm.text' ,
2022-02-24 02:27:53 -07:00
body : normalMessageText1 ,
2022-02-23 20:25:05 -07:00
} ) ;
2022-02-24 02:27:53 -07:00
// Another normal text message
const normalMessageText2 =
'The topography of the Moon has been measured with laser altimetry and stereo image analysis.' ;
const normalMessageEventId2 = await client . sendMessage ( roomId , {
2022-02-23 20:25:05 -07:00
msgtype : 'm.text' ,
2022-02-24 02:27:53 -07:00
body : normalMessageText2 ,
2022-02-23 20:25:05 -07:00
} ) ;
// Test replies
2022-02-24 02:27:53 -07:00
const replyMessageText = ` The concentration of maria on the near side likely reflects the substantially thicker crust of the highlands of the Far Side, which may have formed in a slow-velocity impact of a second moon of Earth a few tens of millions of years after the Moon's formation. ` ;
const replyMessageEventId = await client . sendMessage ( roomId , {
2022-02-23 20:25:05 -07:00
'org.matrix.msc1767.message' : [
{
2022-02-24 02:27:53 -07:00
body : '> <@ericgittertester:my.synapse.server> ${normalMessageText2}' ,
2022-02-23 20:25:05 -07:00
mimetype : 'text/plain' ,
} ,
{
2022-02-24 02:27:53 -07:00
body : ` <mx-reply><blockquote><a href="https://matrix.to/#/ ${ roomId } / ${ normalMessageEventId2 } ?via=my.synapse.server">In reply to</a> <a href="https://matrix.to/#/@ericgittertester:my.synapse.server">@ericgittertester:my.synapse.server</a><br> ${ normalMessageText2 } </blockquote></mx-reply> ${ replyMessageText } ` ,
2022-02-23 20:25:05 -07:00
mimetype : 'text/html' ,
} ,
] ,
2022-02-24 02:27:53 -07:00
body : ` > <@ericgittertester:my.synapse.server> ${ normalMessageText2 } \n \n ${ replyMessageText } ` ,
2022-02-23 20:25:05 -07:00
msgtype : 'm.text' ,
format : 'org.matrix.custom.html' ,
2022-02-24 02:27:53 -07:00
formatted _body : ` <mx-reply><blockquote><a href="https://matrix.to/#/ ${ roomId } / ${ normalMessageEventId2 } ?via=my.synapse.server">In reply to</a> <a href="https://matrix.to/#/@ericgittertester:my.synapse.server">@ericgittertester:my.synapse.server</a><br> ${ normalMessageText2 } </blockquote></mx-reply> ${ replyMessageText } ` ,
2022-02-23 20:25:05 -07:00
'm.relates_to' : {
'm.in_reply_to' : {
2022-02-24 02:27:53 -07:00
event _id : normalMessageEventId2 ,
2022-02-23 20:25:05 -07:00
} ,
} ,
} ) ;
// Test reactions
2022-02-24 02:27:53 -07:00
const reactionText = '😅' ;
2022-02-23 20:25:05 -07:00
await client . sendEvent ( roomId , 'm.reaction' , {
'm.relates_to' : {
rel _type : 'm.annotation' ,
2022-02-24 02:27:53 -07:00
event _id : replyMessageEventId ,
key : reactionText ,
2022-02-23 20:25:05 -07:00
} ,
} ) ;
const archiveUrl = matrixPublicArchiveURLCreator . archiveUrlForDate ( roomId , new Date ( ) ) ;
2022-02-24 02:27:53 -07:00
if ( interactive ) {
console . log ( 'Interactive URL for test' , archiveUrl ) ;
}
2022-02-23 20:25:05 -07:00
const archivePageHtml = await fetchEndpointAsText ( archiveUrl ) ;
2022-02-24 02:27:53 -07:00
const dom = parseHTML ( archivePageHtml ) ;
// Make sure the image message is visible
const imageElement = dom . document . querySelector ( ` [data-event-id=" ${ imageEventId } "] img ` ) ;
assert ( imageElement ) ;
assert . match ( imageElement . getAttribute ( 'src' ) , new RegExp ( ` ^http://.* ` ) ) ;
assert . strictEqual ( imageElement . getAttribute ( 'alt' ) , 'Friction_between_surfaces.jpeg' ) ;
// Make sure the normal message is visible
assert . match (
dom . document . querySelector ( ` [data-event-id=" ${ normalMessageEventId1 } "] ` ) . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( normalMessageText1 ) } .* ` )
) ;
// Make sure the other normal message is visible
assert . match (
dom . document . querySelector ( ` [data-event-id=" ${ normalMessageEventId2 } "] ` ) . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( normalMessageText2 ) } .* ` )
) ;
const replyMessageElement = dom . document . querySelector (
` [data-event-id=" ${ replyMessageEventId } "] `
) ;
// Make sure the reply text is there
assert . match (
replyMessageElement . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( replyMessageText ) } .* ` )
) ;
// Make sure it also includes the message we're replying to
assert . match (
replyMessageElement . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( normalMessageEventId2 ) } .* ` )
) ;
// Make sure the reaction also exists
assert . match (
replyMessageElement . outerHTML ,
new RegExp ( ` .* ${ escapeStringRegexp ( reactionText ) } .* ` )
) ;
2022-02-23 20:25:05 -07:00
} catch ( err ) {
if ( err . body ) {
// FIXME: Remove this try/catch once the matrix-bot-sdk no longer throws
// huge response objects as errors, see
// https://github.com/turt2live/matrix-bot-sdk/pull/158
throw new Error (
` Error occured in matrix-bot-sdk (this new error is to stop it from logging the huge response) statusCode= ${
err . statusCode
} body = $ { JSON . stringify ( err . body ) } `
) ;
}
throw err ;
}
} ) ;
2022-02-22 19:55:42 -07:00
it ( ` can render day back in time from room on remote homeserver we haven't backfilled from ` ) ;
it ( ` will redirect to hour pagination when there are too many messages ` ) ;
2022-02-24 02:27:53 -07:00
it ( ` will render a room with only a day of messages ` ) ;
it (
` will render a room with a sparse amount of messages (a few per day) with no contamination between days `
) ;
2022-02-22 15:06:29 -07:00
} ) ;