@@ -63,6 +63,45 @@ func TestJumpToDateEndpoint(t *testing.T) {
6363 mustCheckEventisReturnedForTime (t , alice , roomID , eventB .AfterTimestamp , "f" , "" )
6464 })
6565
66+ t .Run ("should find next event topologically before given timestamp when all message timestamps are the same" , func (t * testing.T ) {
67+ t .Parallel ()
68+ roomID , _ , _ := createTestRoom (t , alice )
69+
70+ // Join from the application service bridge user so we can use to send
71+ // some messages at a specific time.
72+ as .JoinRoom (t , roomID , []string {"hs1" })
73+
74+ // Send a couple messages with the same timestamp after the other test
75+ // messages in the room.
76+ timeBeforeMessageCreation := time .Now ()
77+ sendMessageWithTimestamp (t , as , alice , roomID , timeBeforeMessageCreation , "messageWithSameTime1" )
78+ messageIDWithSameTime2 := sendMessageWithTimestamp (t , as , alice , roomID , timeBeforeMessageCreation , "messageWithSameTime2" )
79+
80+ // Looking backwards from the time the messages were sent, we should find
81+ // message2. A naive MSC3030 implementation that only sorts by timestamp
82+ // will probably return message1 since it's the first one in the database.
83+ mustCheckEventisReturnedForTime (t , alice , roomID , timeBeforeMessageCreation , "b" , messageIDWithSameTime2 )
84+ })
85+
86+ t .Run ("should find next event topologically after given timestmap when all message timestamps are the same" , func (t * testing.T ) {
87+ t .Parallel ()
88+ roomID , _ , _ := createTestRoom (t , alice )
89+
90+ // Join from the application service bridge user so we can use to send
91+ // some messages at a specific time.
92+ as .JoinRoom (t , roomID , []string {"hs1" })
93+
94+ // Send a couple messages with the same timestamp after the other test
95+ // messages in the room.
96+ timeBeforeMessageCreation := time .Now ()
97+ messageIDWithSameTime1 := sendMessageWithTimestamp (t , as , alice , roomID , timeBeforeMessageCreation , "messageWithSameTime1" )
98+ sendMessageWithTimestamp (t , as , alice , roomID , timeBeforeMessageCreation , "messageWithSameTime2" )
99+
100+ // Looking forwards from the time the messages were sent, we should find
101+ // message1.
102+ mustCheckEventisReturnedForTime (t , alice , roomID , timeBeforeMessageCreation , "f" , messageIDWithSameTime1 )
103+ })
104+
66105 // Just a sanity check that we're not leaking anything from the `/timestamp_to_event` endpoint
67106 t .Run ("should not be able to query a private room you are not a member of" , func (t * testing.T ) {
68107 t .Parallel ()
@@ -139,28 +178,13 @@ func TestJumpToDateEndpoint(t *testing.T) {
139178 timeBeforeRoomCreation := time .Now ()
140179 roomID , _ , _ := createTestRoom (t , alice )
141180
142- // Join from the application service bridge user
181+ // Join from the application service bridge user so we can use it to send
182+ // some messages at a specific time.
143183 as .JoinRoom (t , roomID , []string {"hs1" })
144184
145- // Import a message in the room before the room was created. We have to
146- // use an application service user because they are the only one
147- // allowed to use the `?ts` query parameter.
185+ // Import a message in the room before the room was created
148186 importTime := time .Date (2022 , 01 , 03 , 0 , 0 , 0 , 0 , time .Local )
149- importTimestamp := makeTimestampFromTime (importTime )
150- timestampString := strconv .FormatInt (importTimestamp , 10 )
151- // We can't use as.SendEventSynced(...) because application services can't use the /sync API
152- sendRes := as .DoFunc (t , "PUT" , []string {"_matrix" , "client" , "v3" , "rooms" , roomID , "send" , "m.room.message" , getTxnID ("findEventBeforeCreation-txn" )}, client .WithContentType ("application/json" ), client .WithJSONBody (t , map [string ]interface {}{
153- "body" : "old imported event" ,
154- "msgtype" : "m.text" ,
155- }), client .WithQueries (url.Values {
156- "ts" : []string {timestampString },
157- }))
158- sendBody := client .ParseJSON (t , sendRes )
159- importedEventID := client .GetJSONFieldStr (t , sendBody , "event_id" )
160- // Make sure the imported event has reached the homeserver
161- alice .MustSyncUntil (t , client.SyncReq {}, client .SyncTimelineHas (roomID , func (ev gjson.Result ) bool {
162- return ev .Get ("event_id" ).Str == importedEventID
163- }))
187+ importedEventID := sendMessageWithTimestamp (t , as , alice , roomID , importTime , "old imported event" )
164188
165189 remoteCharlie .JoinRoom (t , roomID , []string {"hs1" })
166190 mustCheckEventisReturnedForTime (t , remoteCharlie , roomID , timeBeforeRoomCreation , "b" , importedEventID )
@@ -237,6 +261,32 @@ func createTestRoom(t *testing.T, c *client.CSAPI) (roomID string, eventA, event
237261 return roomID , eventA , eventB
238262}
239263
264+ func sendMessageWithTimestamp (t * testing.T , as * client.CSAPI , c * client.CSAPI , roomID string , messageTime time.Time , message string ) (messageEventID string ) {
265+ t .Helper ()
266+
267+ timestamp := makeTimestampFromTime (messageTime )
268+ timestampString := strconv .FormatInt (timestamp , 10 )
269+ // We have to use an application service user because they are the only one
270+ // allowed to use the `?ts` query parameter.
271+ //
272+ // We can't use as.SendEventSynced(...) because application services can't use
273+ // the /sync API.
274+ sendRes := as .DoFunc (t , "PUT" , []string {"_matrix" , "client" , "v3" , "rooms" , roomID , "send" , "m.room.message" , getTxnID ("sendMessageWithTimestamp-txn" )}, client .WithContentType ("application/json" ), client .WithJSONBody (t , map [string ]interface {}{
275+ "body" : message ,
276+ "msgtype" : "m.text" ,
277+ }), client .WithQueries (url.Values {
278+ "ts" : []string {timestampString },
279+ }))
280+ sendBody := client .ParseJSON (t , sendRes )
281+ messageEventID = client .GetJSONFieldStr (t , sendBody , "event_id" )
282+ // Make sure the imported event has reached the homeserver
283+ c .MustSyncUntil (t , client.SyncReq {}, client .SyncTimelineHas (roomID , func (ev gjson.Result ) bool {
284+ return ev .Get ("event_id" ).Str == messageEventID
285+ }))
286+
287+ return
288+ }
289+
240290// Fetch event from /timestamp_to_event and ensure it matches the expectedEventId
241291func mustCheckEventisReturnedForTime (t * testing.T , c * client.CSAPI , roomID string , givenTime time.Time , direction string , expectedEventId string ) {
242292 t .Helper ()
0 commit comments