Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions tests/room_timestamp_to_event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ func TestJumpToDateEndpoint(t *testing.T) {
t.Run("should find nothing before the earliest timestamp", func(t *testing.T) {
t.Parallel()
timeBeforeRoomCreation := time.Now()
// Guard so createRoom cannot share this sample's millisecond; a
// backward search there would return m.room.create instead of nothing.
time.Sleep(tsBoundaryGuard)
roomID, _, _ := createTestRoom(t, alice)
mustCheckEventisReturnedForTime(t, alice, roomID, timeBeforeRoomCreation, "b", "")
})
Expand All @@ -76,6 +79,9 @@ func TestJumpToDateEndpoint(t *testing.T) {
deployment.GetFullyQualifiedHomeserverName(t, "hs1"),
})

// Guard so the join cannot share a millisecond with the messages below.
time.Sleep(tsBoundaryGuard)

// Send a couple messages with the same timestamp after the other test
// messages in the room.
timeBeforeMessageCreation := time.Now()
Expand All @@ -98,6 +104,9 @@ func TestJumpToDateEndpoint(t *testing.T) {
deployment.GetFullyQualifiedHomeserverName(t, "hs1"),
})

// Guard so the join cannot share a millisecond with the messages below.
time.Sleep(tsBoundaryGuard)

// Send a couple messages with the same timestamp after the other test
// messages in the room.
timeBeforeMessageCreation := time.Now()
Expand All @@ -113,6 +122,7 @@ func TestJumpToDateEndpoint(t *testing.T) {
t.Run("should not be able to query a private room you are not a member of", func(t *testing.T) {
t.Parallel()
timeBeforeRoomCreation := time.Now()
time.Sleep(tsBoundaryGuard)

// Alice will create the private room
roomID := alice.MustCreateRoom(t, map[string]interface{}{
Expand Down Expand Up @@ -141,6 +151,7 @@ func TestJumpToDateEndpoint(t *testing.T) {
t.Run("should not be able to query a public room you are not a member of", func(t *testing.T) {
t.Parallel()
timeBeforeRoomCreation := time.Now()
time.Sleep(tsBoundaryGuard)

// Alice will create the public room
roomID := alice.MustCreateRoom(t, map[string]interface{}{
Expand Down Expand Up @@ -187,6 +198,7 @@ func TestJumpToDateEndpoint(t *testing.T) {
t.Run("when looking backwards before the room was created, should be able to find event that was imported", func(t *testing.T) {
t.Parallel()
timeBeforeRoomCreation := time.Now()
time.Sleep(tsBoundaryGuard)
roomID, _, _ := createTestRoom(t, alice)

// Join from the application service bridge user so we can use it to send
Expand Down Expand Up @@ -331,6 +343,16 @@ type eventTime struct {
AfterTimestamp time.Time
}

// tsBoundaryGuard is a pause inserted around (before and after) where we create events
// so that `time.Now()` samples and subsequent event `origin_server_ts` don't collide at
// the same millisecond granularity. /timestamp_to_event returns the boundary event
// inclusively (forward picks the earliest event with ts >= query, backward picks the
// latest with ts <= query), so a shared millisecond between events means the wrong
// event can be picked. Adding one whole millisecond to a timestamp always carries it
// into the next millisecond bucket, so 1ms is enough to separate the sample from every
// event stamped after the pause.
const tsBoundaryGuard = 1 * time.Millisecond

func createTestRoom(t *testing.T, c *client.CSAPI) (roomID string, eventA, eventB *eventTime) {
t.Helper()

Expand All @@ -339,26 +361,33 @@ func createTestRoom(t *testing.T, c *client.CSAPI) (roomID string, eventA, event
})

timeBeforeEventA := time.Now()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
timeBeforeEventA := time.Now()
timeBeforeEventA := time.Now()
time.Sleep(tsBoundaryGuard)

time.Sleep(tsBoundaryGuard)
eventAID := c.SendEventSynced(t, roomID, b.Event{
Type: "m.room.message",
Content: map[string]interface{}{
"msgtype": "m.text",
"body": "Message A",
},
})
timeAfterEventA := time.Now()

// timeBeforeEventB doubles as eventA's after-timestamp, so guard it on
// both sides to keep it between the two events.
time.Sleep(tsBoundaryGuard)
timeBeforeEventB := time.Now()
Comment on lines +375 to +376
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we probably need a time.Sleep(tsBoundaryGuard) after the sample for the same reasons (timeBeforeEventB should actually come 1ms before we send event B in all cases)

Suggested change
time.Sleep(tsBoundaryGuard)
timeBeforeEventB := time.Now()
time.Sleep(tsBoundaryGuard)
timeBeforeEventB := time.Now()
time.Sleep(tsBoundaryGuard)

(comment above could use work as well)

time.Sleep(tsBoundaryGuard)
eventBID := c.SendEventSynced(t, roomID, b.Event{
Type: "m.room.message",
Content: map[string]interface{}{
"msgtype": "m.text",
"body": "Message B",
},
})

time.Sleep(tsBoundaryGuard)
timeAfterEventB := time.Now()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
timeAfterEventB := time.Now()
time.Sleep(tsBoundaryGuard)
timeAfterEventB := time.Now()


eventA = &eventTime{EventID: eventAID, BeforeTimestamp: timeBeforeEventA, AfterTimestamp: timeAfterEventA}
eventB = &eventTime{EventID: eventBID, BeforeTimestamp: timeAfterEventA, AfterTimestamp: timeAfterEventB}
eventA = &eventTime{EventID: eventAID, BeforeTimestamp: timeBeforeEventA, AfterTimestamp: timeBeforeEventB}
eventB = &eventTime{EventID: eventBID, BeforeTimestamp: timeBeforeEventB, AfterTimestamp: timeAfterEventB}

return roomID, eventA, eventB
}
Expand Down
Loading