Skip to content

Commit 1889d0a

Browse files
committed
Add tests to ensure MSC3030 functionality
MSC3030: matrix-org/matrix-spec-proposals#3030 Synapse implementation: matrix-org/synapse#9445
1 parent fd752eb commit 1889d0a

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

internal/client/client.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,27 @@ func (c *CSAPI) RegisterUser(t *testing.T, localpart, password string) (userID,
212212
return userID, accessToken
213213
}
214214

215+
// GetEvent fetches the given event from the specified room and returns a typed Event
216+
func (c *CSAPI) GetEvent(t *testing.T, roomID, eventId string) b.Event {
217+
t.Helper()
218+
res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "event", eventId})
219+
body := ParseJSON(t, res)
220+
221+
statKeyRes := gjson.GetBytes(body, "state_key")
222+
var stateKey *string = nil
223+
if statKeyRes.Exists() {
224+
stateKey = b.Ptr(statKeyRes.Str)
225+
}
226+
227+
return b.Event{
228+
Type: GetJSONFieldStr(t, body, "type"),
229+
Sender: GetJSONFieldStr(t, body, "sender"),
230+
StateKey: stateKey,
231+
Content: GetJSONFieldStringMap(t, body, "content"),
232+
Unsigned: GetJSONFieldStringMap(t, body, "unsigned"),
233+
}
234+
}
235+
215236
// MustDo will do the HTTP request and fail the test if the response is not 2xx
216237
func (c *CSAPI) MustDo(t *testing.T, method string, paths []string, jsonBody interface{}) *http.Response {
217238
t.Helper()
@@ -406,6 +427,26 @@ func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string
406427
return arr
407428
}
408429

430+
func GetJSONFieldStringMap(t *testing.T, body []byte, wantKey string) map[string]interface{} {
431+
t.Helper()
432+
433+
res := gjson.GetBytes(body, wantKey)
434+
435+
if !res.Exists() {
436+
t.Fatalf("GetJSONFieldStringMap: key '%s' missing from %s", wantKey, string(body))
437+
}
438+
439+
jsonMap := map[string]interface{}{}
440+
res.ForEach(func(key, value gjson.Result) bool {
441+
jsonMap[key.Str] = value.Str
442+
443+
// Keep iterating
444+
return true
445+
})
446+
447+
return jsonMap
448+
}
449+
409450
// ParseJSON parses a JSON-encoded HTTP Response body into a byte slice
410451
func ParseJSON(t *testing.T, res *http.Response) []byte {
411452
t.Helper()

tests/msc3030_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// +build msc3030
2+
3+
// This file contains tests for a jump to date API endpoint,
4+
// currently experimental feature defined by MSC3030, which you can read here:
5+
// https://github.com/matrix-org/matrix-doc/pull/3030
6+
7+
package tests
8+
9+
import (
10+
"net/url"
11+
"strconv"
12+
"testing"
13+
"time"
14+
15+
"github.com/matrix-org/complement/internal/b"
16+
"github.com/matrix-org/complement/internal/client"
17+
"github.com/sirupsen/logrus"
18+
"github.com/tidwall/gjson"
19+
)
20+
21+
func TestJumpToDateEndpoint(t *testing.T) {
22+
deployment := Deploy(t, b.BlueprintFederationTwoLocalOneRemote)
23+
defer deployment.Destroy(t)
24+
25+
// Create the normal user which will send messages in the room
26+
userID := "@alice:hs1"
27+
alice := deployment.Client(t, "hs1", userID)
28+
29+
roomID := alice.CreateRoom(t, map[string]interface{}{})
30+
alice.JoinRoom(t, roomID, nil)
31+
32+
timeBeforeEventA := time.Now()
33+
eventAID := alice.SendEventSynced(t, roomID, b.Event{
34+
Type: "m.room.message",
35+
Content: map[string]interface{}{
36+
"msgtype": "m.text",
37+
"body": "Message A",
38+
},
39+
})
40+
eventBID := alice.SendEventSynced(t, roomID, b.Event{
41+
Type: "m.room.message",
42+
Content: map[string]interface{}{
43+
"msgtype": "m.text",
44+
"body": "Message A",
45+
},
46+
})
47+
timeAfterEventB := time.Now()
48+
49+
logrus.WithFields(logrus.Fields{
50+
"eventAID": eventAID,
51+
"eventBID": eventBID,
52+
}).Error("see messages")
53+
54+
t.Run("parallel", func(t *testing.T) {
55+
t.Run("should find event after given timestmap", func(t *testing.T) {
56+
checkEventisReturnedForTime(t, alice, roomID, timeBeforeEventA, eventAID)
57+
})
58+
59+
t.Run("should find event before given timestmap", func(t *testing.T) {
60+
checkEventisReturnedForTime(t, alice, roomID, timeAfterEventB, eventBID)
61+
})
62+
63+
})
64+
}
65+
66+
func makeTimestampFromTime(t time.Time) int64 {
67+
return t.UnixNano() / int64(time.Millisecond)
68+
}
69+
70+
func checkEventisReturnedForTime(t *testing.T, c *client.CSAPI, roomID string, givenTime time.Time, expectedEventId string) {
71+
t.Helper()
72+
73+
timestampString := strconv.FormatInt(makeTimestampFromTime(givenTime), 10)
74+
timestampToEventRes := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{
75+
"ts": []string{timestampString},
76+
}))
77+
timestampToEventResBody := client.ParseJSON(t, timestampToEventRes)
78+
79+
actualEventIdRes := gjson.GetBytes(timestampToEventResBody, "event_id")
80+
actualEventId := actualEventIdRes.Str
81+
82+
if actualEventId != expectedEventId {
83+
actualEvent := c.GetEvent(t, roomID, actualEventId)
84+
t.Fatalf("Expected to see %s but received %s\n%+v", expectedEventId, actualEventId, actualEvent)
85+
}
86+
}

0 commit comments

Comments
 (0)