func TestSlackMessageFromUnlinkedUser(t *testing.T) { db := makeDB(t) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } slackChannel := "BOWLINGALLEY" matrixRoom := matrix.NewRoom("!abc123:matrix.org") message := "Shhhhh" slackUser := "******" asToken := "abc123" rooms.Link(matrixRoom, slackChannel) echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } slackRoomMembers := slack.NewRoomMembers() slackRoomMembers.Add(slackChannel, &slack.User{"someone", &MockSlackClient{}}) calledTwice := make(chan struct{}, 1) var invites int32 var botJoins int32 var joins int32 var calls int32 verify := func(req *http.Request) string { if req.URL.Path == "/api/users.info" { return `{"ok": true, "user": {"id": "` + slackUser + `", "name": "someoneonslack"}}` } if req.URL.Path == "/_matrix/client/api/v1/rooms/"+matrixRoom.ID+"/join" { if req.URL.Query().Get("user_id") == "" { atomic.AddInt32(&botJoins, 1) } else { atomic.AddInt32(&joins, 1) } return "" } if req.URL.Path == "/_matrix/client/api/v1/rooms/"+matrixRoom.ID+"/invite" { atomic.AddInt32(&invites, 1) return "" } if req.URL.Path != "/_matrix/client/api/v1/rooms/"+matrixRoom.ID+"/send/m.room.message" { t.Fatalf("Got request to unexpected path %q", req.URL.Path) return "" } if atomic.LoadInt32(&invites) == 0 { t.Errorf("Didn't get expected invite before message send") } if atomic.LoadInt32(&joins) == 0 { t.Errorf("Didn't get expected join before message send") } query := req.URL.Query() assertUrlValueEquals(t, query, "access_token", asToken) assertUrlValueEquals(t, query, "user_id", "@prefix_someoneonslack:my.server") b, err := ioutil.ReadAll(req.Body) if err != nil { t.Fatalf("Error reading request body: %v", err) } var content matrix.TextMessageContent if err := json.Unmarshal(b, &content); err != nil { t.Fatalf("Error unmarshaling json: %v", err) } if content.MsgType != "m.text" { t.Errorf("Msgtype: want %q got %q", "m.text", content.MsgType) } if content.Body != message { t.Errorf("Message: want %q got %q", message, content.Body) } callsAfter := atomic.AddInt32(&calls, 1) if callsAfter == 2 { calledTwice <- struct{}{} } return "" } client := http.Client{ Transport: &spyRoundTripper{verify}, } matrixUsers := matrix.NewUsers() bridge := Bridge{users, rooms, slackRoomMembers, matrixUsers, client, echoSuppresser, Config{ MatrixASAccessToken: asToken, UserPrefix: "@prefix_", HomeserverBaseURL: "https://my.server", HomeserverName: "my.server", }} bridge.OnSlackMessage(slack.Message{ Type: "message", Channel: "BOWLINGALLEY", TS: "10", User: slackUser, Text: message, }) bridge.OnSlackMessage(slack.Message{ Type: "message", Channel: "BOWLINGALLEY", TS: "11", User: slackUser, Text: message, }) select { case _ = <-calledTwice: if got := atomic.LoadInt32(&joins); got != 1 { t.Errorf("join count: want: %d, got: %d", 1, got) } if got := atomic.LoadInt32(&botJoins); got != 1 { t.Errorf("bot join count: want: %d, got: %d", 1, got) } return case _ = <-time.After(50 * time.Millisecond): t.Fatalf("Didn't get expected calls") } }
func TestMatrixMessageFromUnlinkedUser(t *testing.T) { db := makeDB(t) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } slackChannel := "BOWLINGALLEY" message := "It's Nancy!" matrixUser := "******" matrixRoom := matrix.NewRoom("!abc123:matrix.org") rooms.Link(matrixRoom, slackChannel) echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } slackRoomMembers := slack.NewRoomMembers() slackRoomMembers.Add(slackChannel, &slack.User{"someone", &MockSlackClient{}}) var calls int32 called := make(chan struct{}, 1) verify := func(req *http.Request) string { b, err := ioutil.ReadAll(req.Body) if err != nil { t.Fatalf("Error reading request body: %v", err) } v, err := url.ParseQuery(string(b)) if err != nil { t.Fatalf("Error parsing request body: %v", err) } assertUrlValueEquals(t, v, "token", "slack_access_token") assertUrlValueEquals(t, v, "channel", slackChannel) assertUrlValueEquals(t, v, "text", message) assertUrlValueEquals(t, v, "as_user", "false") assertUrlValueEquals(t, v, "username", matrixUser) if c := atomic.LoadInt32(&calls); c == 0 { if got, ok := v["icon_url"]; ok { t.Errorf("Want icon_url absent, got: %v", got) } } else if c == 1 { assertUrlValueEquals(t, v, "icon_url", "https://hs.url/_matrix/media/v1/download/st.andrews/sean.jpg") } atomic.AddInt32(&calls, 1) if calls == 2 { called <- struct{}{} } return "" } client := http.Client{ Transport: &spyRoundTripper{verify}, } bridge := Bridge{users, rooms, slackRoomMembers, nil, client, echoSuppresser, Config{ HomeserverBaseURL: "https://hs.url", }} bridge.OnMatrixRoomMessage(matrix.RoomMessage{ Type: "m.room.message", Content: []byte(`{"msgtype": "m.text", "body": "` + message + `"}`), UserID: matrixUser, RoomID: matrixRoom.ID, }) bridge.OnMatrixRoomMember(matrix.RoomMemberEvent{ Type: "m.room.member", Content: matrix.UserInfo{ Membership: "join", AvatarURL: "mxc://st.andrews/sean.jpg", }, StateKey: matrixUser, UserID: matrixUser, RoomID: matrixRoom.ID, }) bridge.OnMatrixRoomMessage(matrix.RoomMessage{ Type: "m.room.message", Content: []byte(`{"msgtype": "m.text", "body": "` + message + `"}`), UserID: matrixUser, RoomID: matrixRoom.ID, }) select { case _ = <-called: return case _ = <-time.After(50 * time.Millisecond): t.Fatalf("Didn't get expected calls (2), got: %d", atomic.LoadInt32(&calls)) } }