From 9da250f6074b820a592d3e1d78887e1e548c632f Mon Sep 17 00:00:00 2001 From: Nikos Filippakis Date: Wed, 1 Jul 2020 18:59:30 +0200 Subject: [PATCH] Integration test to confirm bot can join a room and respond to a command Signed-off-by: Nikos Filippakis --- clients/bot_client.go | 2 +- goneb_services_test.go | 132 ++++++++++++++++++++++++++++++++++++++--- testutil_test.go | 20 ++++--- 3 files changed, 137 insertions(+), 17 deletions(-) diff --git a/clients/bot_client.go b/clients/bot_client.go index bcae08d..219f2ac 100644 --- a/clients/bot_client.go +++ b/clients/bot_client.go @@ -32,7 +32,7 @@ func (botClient *BotClient) InitOlmMachine(client *mautrix.Client, nebStore *mat if sdb, ok := database.GetServiceDB().(*database.ServiceDB); ok { // Create an SQL crypto store based on the ServiceDB used db, dialect := sdb.GetSQLDb() - sqlCryptoStore := crypto.NewSQLCryptoStore(db, dialect, client.DeviceID, []byte(client.DeviceID.String()), cryptoLogger) + sqlCryptoStore := crypto.NewSQLCryptoStore(db, dialect, client.DeviceID, []byte(client.DeviceID.String()+"pickle"), cryptoLogger) // Try to create the tables if they are missing if err = sqlCryptoStore.CreateTables(); err != nil { return diff --git a/goneb_services_test.go b/goneb_services_test.go index 3dcf5d9..130edd1 100644 --- a/goneb_services_test.go +++ b/goneb_services_test.go @@ -4,14 +4,13 @@ import ( "bytes" "net/http" "net/http/httptest" - "os" + "strings" "testing" ) -var mux = http.NewServeMux() -var mxTripper = newMatrixTripper() - -func TestMain(m *testing.M) { +func TestConfigureClient(t *testing.T) { + mux := http.NewServeMux() + mxTripper := newMatrixTripper() setup(envVars{ BaseURL: "http://go.neb", DatabaseType: "sqlite3", @@ -19,11 +18,7 @@ func TestMain(m *testing.M) { }, mux, &http.Client{ Transport: mxTripper, }) - exitCode := m.Run() - os.Exit(exitCode) -} -func TestConfigureClient(t *testing.T) { mxTripper.ClearHandlers() mockWriter := httptest.NewRecorder() syncChan := make(chan string) @@ -54,3 +49,122 @@ func TestConfigureClient(t *testing.T) { <-syncChan } + +func TestRespondToEcho(t *testing.T) { + mux := http.NewServeMux() + mxTripper := newMatrixTripper() + setup(envVars{ + BaseURL: "http://go.neb", + DatabaseType: "sqlite3", + DatabaseURL: ":memory:", + }, mux, &http.Client{ + Transport: mxTripper, + }) + + mxTripper.ClearHandlers() + mockWriter := httptest.NewRecorder() + reqChan := make(chan string) + mxTripper.HandlePOSTFilter("@link:hyrule") + mxTripper.Handle("GET", "/_matrix/client/r0/sync", + func(req *http.Request) (*http.Response, error) { + reqBody := <-reqChan + return newResponse(200, reqBody), nil + }, + ) + mxTripper.Handle("POST", "/_matrix/client/r0/keys/upload", func(req *http.Request) (*http.Response, error) { + return newResponse(200, `{}`), nil + }) + + var joinedRoom string + var joinedRoomBody []byte + mxTripper.Handle("POST", "/_matrix/client/r0/join/*", func(req *http.Request) (*http.Response, error) { + parts := strings.Split(req.URL.String(), "/") + joinedRoom = parts[len(parts)-1] + n, _ := req.Body.Read(joinedRoomBody) + joinedRoomBody = joinedRoomBody[:n] + return newResponse(200, `{}`), nil + }) + + var roomMsgBody []byte + mxTripper.Handle("PUT", "/_matrix/client/r0/rooms/!greatdekutree:hyrule/send/m.room.message/*", func(req *http.Request) (*http.Response, error) { + n, _ := req.Body.Read(roomMsgBody) + roomMsgBody = roomMsgBody[:n] + return newResponse(200, `{}`), nil + }) + + // configure the client + clientConfigReq, _ := http.NewRequest("POST", "http://go.neb/admin/configureClient", bytes.NewBufferString(` + { + "UserID":"@link:hyrule", + "HomeserverURL":"http://hyrule.loz", + "AccessToken":"dangeroustogoalone", + "Sync":true, + "AutoJoinRooms":true + }`)) + mux.ServeHTTP(mockWriter, clientConfigReq) + + // configure the echo service + serviceConfigReq, _ := http.NewRequest("POST", "http://go.neb/admin/configureService", bytes.NewBufferString(` + { + "Type": "echo", + "Id": "test_echo_service", + "UserID": "@link:hyrule", + "Config": {} + }`)) + mux.ServeHTTP(mockWriter, serviceConfigReq) + + // get the initial syncs out of the way + reqChan <- `{"next_batch":"11_22_33_44", "rooms": {}}` + reqChan <- `{"next_batch":"11_22_33_44", "rooms": {}}` + + // send neb an invite to a room + reqChan <- `{ + "next_batch":"11_22_33_44", + "rooms": { + "invite": { + "!greatdekutree:hyrule": {"invite_state": {"events": [{ + "type": "m.room.member", + "sender": "@navi:hyrule", + "content": {"membership": "invite"}, + "state_key": "@link:hyrule", + "origin_server_ts": 10000, + "unsigned": {"age": 100}, + "event_id": "evt123" + }]}}} + } + }` + + // wait for it to be processed + reqChan <- `{"next_batch":"11_22_33_44", "rooms": {}}` + + expectedRoom := "%21greatdekutree:hyrule" + if joinedRoom != expectedRoom { + t.Errorf("Expected join for room %v, got %v", expectedRoom, joinedRoom) + } + if expectedBody := `{"inviter":"@navi:hyrule"}`; string(joinedRoomBody) != expectedBody { + t.Errorf("Expected join message body to be %v, got %v", expectedBody, string(joinedRoomBody)) + } + + // send neb an !echo message + reqChan <- `{ + "next_batch":"11_22_33_44", + "rooms": { + "join": { + "!greatdekutree:hyrule": {"timeline": {"events": [{ + "type": "m.room.message", + "sender": "@navi:hyrule", + "content": {"body": "!echo save zelda", "msgtype": "m.text"}, + "origin_server_ts": 10000, + "unsigned": {"age": 100}, + "event_id": "evt124" + }]}}} + } + }` + + // wait for it to be processed + reqChan <- `{"next_batch":"11_22_33_44", "rooms": {}}` + + if expectedEchoResp := `{"msgtype":"m.notice","body":"save zelda"}`; string(roomMsgBody) != expectedEchoResp { + t.Errorf("Expected echo response to be `%v`, got `%v`", expectedEchoResp, string(roomMsgBody)) + } +} diff --git a/testutil_test.go b/testutil_test.go index d74f08b..cb9b209 100644 --- a/testutil_test.go +++ b/testutil_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "maunium.net/go/mautrix/id" ) @@ -30,14 +31,19 @@ func newMatrixTripper() *matrixTripper { func (rt *matrixTripper) RoundTrip(req *http.Request) (*http.Response, error) { key := req.Method + " " + req.URL.Path - h := rt.handlers[key] - if h == nil { - panic(fmt.Sprintf( - "RoundTrip: Unhandled request: %s\nHandlers: %d", - key, len(rt.handlers), - )) + if handler, ok := rt.handlers[key]; ok { + return handler(req) } - return h(req) + for strMatch, handler := range rt.handlers { + // try to match key with wildcard handlers + if strMatch[len(strMatch)-1] == '*' && strings.HasPrefix(key, strMatch[:len(strMatch)-1]) { + return handler(req) + } + } + panic(fmt.Sprintf( + "RoundTrip: Unhandled request: %s\nHandlers: %d", + key, len(rt.handlers), + )) } func (rt *matrixTripper) Handle(method, path string, handler func(req *http.Request) (*http.Response, error)) {