diff --git a/cmd/create-room-events/main.go b/cmd/create-room-events/main.go deleted file mode 100644 index 23b44193..00000000 --- a/cmd/create-room-events/main.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Generate a list of matrix room events for load testing. -// Writes the events to stdout by default. -package main - -import ( - "encoding/base64" - "encoding/json" - "flag" - "fmt" - "os" - "strings" - "time" - - "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/gomatrixserverlib" - "golang.org/x/crypto/ed25519" -) - -const usage = `Usage: %s - -Generate a list of matrix room events for load testing. -Writes the events to stdout separated by new lines - -Arguments: - -` - -var ( - serverName = flag.String("server-name", "localhost", "The name of the matrix server to generate events for") - keyID = flag.String("key-id", "ed25519:auto", "The ID of the key used to sign the events") - privateKeyString = flag.String("private-key", defaultKey, "Base64 encoded private key to sign events with") - roomID = flag.String("room-id", "!roomid:$SERVER_NAME", "The room ID to generate events in") - userID = flag.String("user-id", "@userid:$SERVER_NAME", "The user ID to use as the event sender") - messageCount = flag.Int("message-count", 10, "The number of m.room.messsage events to generate") - format = flag.String("Format", "InputRoomEvent", "The output format to use for the messages: InputRoomEvent or Event") - ver = flag.String("version", string(gomatrixserverlib.RoomVersionV1), "Room version to generate events as") -) - -// By default we use a private key of 0. -const defaultKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - -var privateKey ed25519.PrivateKey -var emptyString = "" -var now time.Time -var b gomatrixserverlib.EventBuilder -var eventID int - -func main() { - flag.Usage = func() { - fmt.Fprintf(os.Stderr, usage, os.Args[0]) - flag.PrintDefaults() - } - - flag.Parse() - *userID = strings.Replace(*userID, "$SERVER_NAME", *serverName, 1) - *roomID = strings.Replace(*roomID, "$SERVER_NAME", *serverName, 1) - - // Decode the ed25519 private key. - privateKeyBytes, err := base64.RawStdEncoding.DecodeString(*privateKeyString) - if err != nil { - panic(err) - } - privateKey = ed25519.PrivateKey(privateKeyBytes) - - // Build a m.room.create event. - b.Sender = *userID - b.RoomID = *roomID - b.Type = "m.room.create" - b.StateKey = &emptyString - b.SetContent(map[string]string{"creator": *userID}) // nolint: errcheck - create := buildAndOutput() - - // Build a m.room.member event. - b.Type = "m.room.member" - b.StateKey = userID - b.SetContent(map[string]string{"membership": gomatrixserverlib.Join}) // nolint: errcheck - b.AuthEvents = []gomatrixserverlib.EventReference{create} - member := buildAndOutput() - - // Build a number of m.room.message events. - b.Type = "m.room.message" - b.StateKey = nil - b.SetContent(map[string]string{"body": "Test Message"}) // nolint: errcheck - b.AuthEvents = []gomatrixserverlib.EventReference{create, member} - for i := 0; i < *messageCount; i++ { - buildAndOutput() - } -} - -// Build an event and write the event to the output. -func buildAndOutput() gomatrixserverlib.EventReference { - eventID++ - now = time.Unix(0, 0) - name := gomatrixserverlib.ServerName(*serverName) - key := gomatrixserverlib.KeyID(*keyID) - - event, err := b.Build( - now, name, key, privateKey, - gomatrixserverlib.RoomVersion(*ver), - ) - if err != nil { - panic(err) - } - writeEvent(event) - reference := event.EventReference() - b.PrevEvents = []gomatrixserverlib.EventReference{reference} - b.Depth++ - return reference -} - -// Write an event to the output. -func writeEvent(event *gomatrixserverlib.Event) { - encoder := json.NewEncoder(os.Stdout) - if *format == "InputRoomEvent" { - var ire api.InputRoomEvent - ire.Kind = api.KindNew - ire.Event = event.Headered(gomatrixserverlib.RoomVersion(*ver)) - authEventIDs := []string{} - for _, ref := range b.AuthEvents.([]gomatrixserverlib.EventReference) { - authEventIDs = append(authEventIDs, ref.EventID) - } - ire.AuthEventIDs = authEventIDs - if err := encoder.Encode(ire); err != nil { - panic(err) - } - } else if *format == "Event" { - if err := encoder.Encode(event); err != nil { - panic(err) - } - } else { - panic(fmt.Errorf("Format %q is not valid, must be %q or %q", *format, "InputRoomEvent", "Event")) - } -} diff --git a/cmd/kafka-producer/main.go b/cmd/kafka-producer/main.go deleted file mode 100644 index 18ee3cdf..00000000 --- a/cmd/kafka-producer/main.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bufio" - "flag" - "fmt" - "os" - "strings" - - sarama "github.com/Shopify/sarama" -) - -const usage = `Usage: %s - -Reads a list of newline separated messages from stdin and writes them to a single partition in kafka. - -Arguments: - -` - -var ( - brokerList = flag.String("brokers", os.Getenv("KAFKA_PEERS"), "The comma separated list of brokers in the Kafka cluster. You can also set the KAFKA_PEERS environment variable") - topic = flag.String("topic", "", "REQUIRED: the topic to produce to") - partition = flag.Int("partition", 0, "The partition to produce to. All the messages will be written to this partition.") -) - -func main() { - flag.Usage = func() { - fmt.Fprintf(os.Stderr, usage, os.Args[0]) - flag.PrintDefaults() - } - - flag.Parse() - - if *brokerList == "" { - fmt.Fprintln(os.Stderr, "no -brokers specified. Alternatively, set the KAFKA_PEERS environment variable") - os.Exit(1) - } - - if *topic == "" { - fmt.Fprintln(os.Stderr, "no -topic specified") - os.Exit(1) - } - - config := sarama.NewConfig() - config.Producer.RequiredAcks = sarama.WaitForAll - config.Producer.Return.Successes = true - config.Producer.Partitioner = sarama.NewManualPartitioner - - producer, err := sarama.NewSyncProducer(strings.Split(*brokerList, ","), config) - if err != nil { - fmt.Fprintln(os.Stderr, "Failed to open Kafka producer:", err) - os.Exit(1) - } - defer func() { - if err := producer.Close(); err != nil { - fmt.Fprintln(os.Stderr, "Failed to close Kafka producer cleanly:", err) - } - }() - - scanner := bufio.NewScanner(os.Stdin) - for scanner.Scan() { - line := scanner.Bytes() - message := &sarama.ProducerMessage{ - Topic: *topic, - Partition: int32(*partition), - Value: sarama.ByteEncoder(line), - } - if _, _, err := producer.SendMessage(message); err != nil { - fmt.Fprintln(os.Stderr, "Failed to send message:", err) - os.Exit(1) - } - - } - if err := scanner.Err(); err != nil { - fmt.Fprintln(os.Stderr, "reading standard input:", err) - } - -} diff --git a/cmd/mediaapi-integration-tests/TESTS.md b/cmd/mediaapi-integration-tests/TESTS.md deleted file mode 100644 index 82777f45..00000000 --- a/cmd/mediaapi-integration-tests/TESTS.md +++ /dev/null @@ -1,69 +0,0 @@ -# Media API Tests - -## Implemented - -* functional - * upload - * normal case - * download - * local file - * existing - * non-existing - * remote file - * existing - * thumbnail - * original file formats - * JPEG - * local file - * existing - * remote file - * existing - * cache - * cold - * hot - * pre-generation according to configuration - * scale - * crop - * dynamic generation - * cold cache - * larger than original - * scale - -## TODO - -* functional - * upload - * file too large - * 0-byte file? - * invalid filename - * invalid content-type - * download - * invalid origin - * invalid media id - * thumbnail - * original file formats - * GIF - * PNG - * BMP - * SVG - * PDF - * TIFF - * WEBP - * local file - * non-existing - * remote file - * non-existing - * pre-generation according to configuration - * manual verification + hash check for regressions? - * dynamic generation - * hot cache - * limit on dimensions? - * 0x0 - * crop -* load - * 100 parallel requests - * same file - * different local files - * different remote files - * pre-generated thumbnails - * non-pre-generated thumbnails diff --git a/cmd/mediaapi-integration-tests/main.go b/cmd/mediaapi-integration-tests/main.go deleted file mode 100644 index 8a5a0d54..00000000 --- a/cmd/mediaapi-integration-tests/main.go +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path" - "path/filepath" - "time" - - "github.com/matrix-org/dendrite/internal/test" - "github.com/matrix-org/gomatrixserverlib" - "gopkg.in/yaml.v2" -) - -var ( - // How long to wait for the server to write the expected output messages. - // This needs to be high enough to account for the time it takes to create - // the postgres database tables which can take a while on travis. - timeoutString = test.Defaulting(os.Getenv("TIMEOUT"), "10s") - // The name of maintenance database to connect to in order to create the test database. - postgresDatabase = test.Defaulting(os.Getenv("POSTGRES_DATABASE"), "postgres") - // The name of the test database to create. - testDatabaseName = test.Defaulting(os.Getenv("DATABASE_NAME"), "mediaapi_test") - // Postgres docker container name (for running psql). If not set, psql must be in PATH. - postgresContainerName = os.Getenv("POSTGRES_CONTAINER") - // Test image to be uploaded/downloaded - testJPEG = test.Defaulting(os.Getenv("TEST_JPEG_PATH"), "cmd/mediaapi-integration-tests/totem.jpg") - kafkaURI = test.Defaulting(os.Getenv("KAFKA_URIS"), "localhost:9092") -) - -var thumbnailSizes = (` -- width: 32 - height: 32 - method: crop -- width: 96 - height: 96 - method: crop -- width: 320 - height: 240 - method: scale -- width: 640 - height: 480 - method: scale -- width: 800 - height: 600 - method: scale -`) - -const serverType = "media-api" - -const testMediaID = "1VuVy8u_hmDllD8BrcY0deM34Bl7SPJeY9J6BkMmpx0" -const testContentType = "image/jpeg" -const testOrigin = "localhost:18001" - -var testDatabaseTemplate = "dbname=%s sslmode=disable binary_parameters=yes" - -var timeout time.Duration - -var port = 10000 - -func startMediaAPI(suffix string, dynamicThumbnails bool) (*exec.Cmd, chan error, *exec.Cmd, string, string) { - dir, err := ioutil.TempDir("", serverType+"-server-test"+suffix) - if err != nil { - panic(err) - } - - proxyAddr := "localhost:1800" + suffix - - database := fmt.Sprintf(testDatabaseTemplate, testDatabaseName+suffix) - cfg, nextPort, err := test.MakeConfig(dir, kafkaURI, database, "localhost", port) - if err != nil { - panic(err) - } - cfg.Global.ServerName = gomatrixserverlib.ServerName(proxyAddr) - cfg.MediaAPI.DynamicThumbnails = dynamicThumbnails - if err = yaml.Unmarshal([]byte(thumbnailSizes), &cfg.MediaAPI.ThumbnailSizes); err != nil { - panic(err) - } - - port = nextPort - if err = test.WriteConfig(cfg, dir); err != nil { - panic(err) - } - - serverArgs := []string{ - "--config", filepath.Join(dir, test.ConfigFile), - } - - databases := []string{ - testDatabaseName + suffix, - } - - proxyCmd, _ := test.StartProxy(proxyAddr, cfg) - - test.InitDatabase( - postgresDatabase, - postgresContainerName, - databases, - ) - - cmd, cmdChan := test.CreateBackgroundCommand( - filepath.Join(filepath.Dir(os.Args[0]), "dendrite-"+serverType+"-server"), - serverArgs, - ) - - fmt.Printf("==TESTSERVER== STARTED %v -> %v : %v\n", proxyAddr, cfg.MediaAPI.InternalAPI.Listen, dir) - return cmd, cmdChan, proxyCmd, proxyAddr, dir -} - -func cleanUpServer(cmd *exec.Cmd, dir string) { - // ensure server is dead, only cleaning up so don't care about errors this returns - cmd.Process.Kill() // nolint: errcheck - if err := os.RemoveAll(dir); err != nil { - fmt.Printf("WARNING: Failed to remove temporary directory %v: %q\n", dir, err) - } -} - -// Runs a battery of media API server tests -// The tests will pause at various points in this list to conduct tests on the HTTP responses before continuing. -func main() { - fmt.Println("==TESTING==", os.Args[0]) - - var err error - timeout, err = time.ParseDuration(timeoutString) - if err != nil { - fmt.Printf("ERROR: Invalid timeout string %v: %q\n", timeoutString, err) - return - } - - // create server1 with only pre-generated thumbnails allowed - server1Cmd, server1CmdChan, server1ProxyCmd, server1ProxyAddr, server1Dir := startMediaAPI("1", false) - defer cleanUpServer(server1Cmd, server1Dir) - defer server1ProxyCmd.Process.Kill() // nolint: errcheck - testDownload(server1ProxyAddr, server1ProxyAddr, "doesnotexist", 404, server1CmdChan) - - // upload a JPEG file - testUpload( - server1ProxyAddr, testJPEG, - ) - - // download that JPEG file - testDownload(server1ProxyAddr, testOrigin, testMediaID, 200, server1CmdChan) - - // thumbnail that JPEG file - testThumbnail(64, 64, "crop", server1ProxyAddr, server1CmdChan) - - // create server2 with dynamic thumbnail generation - server2Cmd, server2CmdChan, server2ProxyCmd, server2ProxyAddr, server2Dir := startMediaAPI("2", true) - defer cleanUpServer(server2Cmd, server2Dir) - defer server2ProxyCmd.Process.Kill() // nolint: errcheck - testDownload(server2ProxyAddr, server2ProxyAddr, "doesnotexist", 404, server2CmdChan) - - // pre-generated thumbnail that JPEG file via server2 - testThumbnail(800, 600, "scale", server2ProxyAddr, server2CmdChan) - - // download that JPEG file via server2 - testDownload(server2ProxyAddr, testOrigin, testMediaID, 200, server2CmdChan) - - // dynamic thumbnail that JPEG file via server2 - testThumbnail(1920, 1080, "scale", server2ProxyAddr, server2CmdChan) - - // thumbnail that JPEG file via server2 - testThumbnail(10000, 10000, "scale", server2ProxyAddr, server2CmdChan) - -} - -func getMediaURI(host, endpoint, query string, components []string) string { - pathComponents := []string{host, "_matrix/media/v1", endpoint} - pathComponents = append(pathComponents, components...) - return "https://" + path.Join(pathComponents...) + query -} - -func testUpload(host, filePath string) { - fmt.Printf("==TESTING== upload %v to %v\n", filePath, host) - file, err := os.Open(filePath) - defer file.Close() // nolint: errcheck, staticcheck, megacheck - if err != nil { - panic(err) - } - filename := filepath.Base(filePath) - stat, err := file.Stat() - if os.IsNotExist(err) { - panic(err) - } - fileSize := stat.Size() - - req, err := http.NewRequest( - "POST", - getMediaURI(host, "upload", "?filename="+filename, nil), - file, - ) - if err != nil { - panic(err) - } - req.ContentLength = fileSize - req.Header.Set("Content-Type", testContentType) - - wantedBody := `{"content_uri": "mxc://localhost:18001/` + testMediaID + `"}` - testReq := &test.Request{ - Req: req, - WantedStatusCode: 200, - WantedBody: test.CanonicalJSONInput([]string{wantedBody})[0], - } - if err := testReq.Do(); err != nil { - panic(err) - } - fmt.Printf("==TESTING== upload %v to %v PASSED\n", filePath, host) -} - -func testDownload(host, origin, mediaID string, wantedStatusCode int, serverCmdChan chan error) { - req, err := http.NewRequest( - "GET", - getMediaURI(host, "download", "", []string{ - origin, - mediaID, - }), - nil, - ) - if err != nil { - panic(err) - } - testReq := &test.Request{ - Req: req, - WantedStatusCode: wantedStatusCode, - WantedBody: "", - } - testReq.Run(fmt.Sprintf("download mxc://%v/%v from %v", origin, mediaID, host), timeout, serverCmdChan) -} - -func testThumbnail(width, height int, resizeMethod, host string, serverCmdChan chan error) { - query := fmt.Sprintf("?width=%v&height=%v", width, height) - if resizeMethod != "" { - query += "&method=" + resizeMethod - } - req, err := http.NewRequest( - "GET", - getMediaURI(host, "thumbnail", query, []string{ - testOrigin, - testMediaID, - }), - nil, - ) - if err != nil { - panic(err) - } - testReq := &test.Request{ - Req: req, - WantedStatusCode: 200, - WantedBody: "", - } - testReq.Run(fmt.Sprintf("thumbnail mxc://%v/%v%v from %v", testOrigin, testMediaID, query, host), timeout, serverCmdChan) -} diff --git a/cmd/mediaapi-integration-tests/totem.jpg b/cmd/mediaapi-integration-tests/totem.jpg deleted file mode 100644 index 9cc2d424..00000000 Binary files a/cmd/mediaapi-integration-tests/totem.jpg and /dev/null differ diff --git a/cmd/roomserver-integration-tests/main.go b/cmd/roomserver-integration-tests/main.go deleted file mode 100644 index ff3f06b6..00000000 --- a/cmd/roomserver-integration-tests/main.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "encoding/json" - - "net/http" - - "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/dendrite/internal/test" - "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/dendrite/roomserver/inthttp" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/gomatrixserverlib" -) - -var ( - // Path to where kafka is installed. - kafkaDir = defaulting(os.Getenv("KAFKA_DIR"), "kafka") - // The URI the kafka zookeeper is listening on. - zookeeperURI = defaulting(os.Getenv("ZOOKEEPER_URI"), "localhost:2181") - // The URI the kafka server is listening on. - kafkaURI = defaulting(os.Getenv("KAFKA_URIS"), "localhost:9092") - // How long to wait for the roomserver to write the expected output messages. - // This needs to be high enough to account for the time it takes to create - // the postgres database tables which can take a while on travis. - timeoutString = defaulting(os.Getenv("TIMEOUT"), "60s") - // Timeout for http client - timeoutHTTPClient = defaulting(os.Getenv("TIMEOUT_HTTP"), "30s") - // The name of maintenance database to connect to in order to create the test database. - postgresDatabase = defaulting(os.Getenv("POSTGRES_DATABASE"), "postgres") - // The name of the test database to create. - testDatabaseName = defaulting(os.Getenv("DATABASE_NAME"), "roomserver_test") - // The postgres connection config for connecting to the test database. - testDatabase = defaulting(os.Getenv("DATABASE"), fmt.Sprintf("dbname=%s binary_parameters=yes", testDatabaseName)) -) - -var exe = test.KafkaExecutor{ - ZookeeperURI: zookeeperURI, - KafkaDirectory: kafkaDir, - KafkaURI: kafkaURI, - // Send stdout and stderr to our stderr so that we see error messages from - // the kafka process. - OutputWriter: os.Stderr, -} - -func defaulting(value, defaultValue string) string { - if value == "" { - value = defaultValue - } - return value -} - -var ( - timeout time.Duration - timeoutHTTP time.Duration -) - -func init() { - var err error - timeout, err = time.ParseDuration(timeoutString) - if err != nil { - panic(err) - } - timeoutHTTP, err = time.ParseDuration(timeoutHTTPClient) - if err != nil { - panic(err) - } -} - -func createDatabase(database string) error { - cmd := exec.Command("psql", postgresDatabase) - cmd.Stdin = strings.NewReader( - fmt.Sprintf("DROP DATABASE IF EXISTS %s; CREATE DATABASE %s;", database, database), - ) - // Send stdout and stderr to our stderr so that we see error messages from - // the psql process - cmd.Stdout = os.Stderr - cmd.Stderr = os.Stderr - return cmd.Run() -} - -// runAndReadFromTopic runs a command and waits for a number of messages to be -// written to a kafka topic. It returns if the command exits, the number of -// messages is reached or after a timeout. It kills the command before it returns. -// It returns a list of the messages read from the command on success or an error -// on failure. -func runAndReadFromTopic(runCmd *exec.Cmd, readyURL string, doInput func(), topic string, count int, checkQueryAPI func()) ([]string, error) { - type result struct { - // data holds all of stdout on success. - data []byte - // err is set on failure. - err error - } - done := make(chan result) - readCmd := exec.Command( - filepath.Join(kafkaDir, "bin", "kafka-console-consumer.sh"), - "--bootstrap-server", kafkaURI, - "--topic", topic, - "--from-beginning", - "--max-messages", fmt.Sprintf("%d", count), - ) - // Send stderr to our stderr so the user can see any error messages. - readCmd.Stderr = os.Stderr - - // Kill both processes before we exit. - defer func() { runCmd.Process.Kill() }() // nolint: errcheck - defer func() { readCmd.Process.Kill() }() // nolint: errcheck - - // Run the command, read the messages and wait for a timeout in parallel. - go func() { - // Read all of stdout. - defer func() { - if err := recover(); err != nil { - if errv, ok := err.(error); ok { - done <- result{nil, errv} - } else { - panic(err) - } - } - }() - data, err := readCmd.Output() - checkQueryAPI() - done <- result{data, err} - }() - go func() { - err := runCmd.Run() - done <- result{nil, err} - }() - go func() { - time.Sleep(timeout) - done <- result{nil, fmt.Errorf("Timeout reading %d messages from topic %q", count, topic)} - }() - - // Poll the HTTP listener of the process waiting for it to be ready to receive requests. - ready := make(chan struct{}) - go func() { - delay := 10 * time.Millisecond - for { - time.Sleep(delay) - if delay < 100*time.Millisecond { - delay *= 2 - } - resp, err := http.Get(readyURL) - if err != nil { - continue - } - if resp.StatusCode == 200 { - break - } - } - ready <- struct{}{} - }() - - // Wait for the roomserver to be ready to receive input or for it to crash. - select { - case <-ready: - case r := <-done: - return nil, r.err - } - - // Write the input now that the server is running. - doInput() - - // Wait for one of the tasks to finsh. - r := <-done - - if r.err != nil { - return nil, r.err - } - - // The kafka console consumer writes a newline character after each message. - // So we split on newline characters - lines := strings.Split(string(r.data), "\n") - if len(lines) > 0 { - // Remove the blank line at the end of the data. - lines = lines[:len(lines)-1] - } - return lines, nil -} - -func writeToRoomServer(input []string, roomserverURL string) error { - var request api.InputRoomEventsRequest - var response api.InputRoomEventsResponse - var err error - request.InputRoomEvents = make([]api.InputRoomEvent, len(input)) - for i := range input { - if err = json.Unmarshal([]byte(input[i]), &request.InputRoomEvents[i]); err != nil { - return err - } - } - x, err := inthttp.NewRoomserverClient(roomserverURL, &http.Client{Timeout: timeoutHTTP}, nil) - if err != nil { - return err - } - x.InputRoomEvents(context.Background(), &request, &response) - return response.Err() -} - -// testRoomserver is used to run integration tests against a single roomserver. -// It creates new kafka topics for the input and output of the roomserver. -// It writes the input messages to the input kafka topic, formatting each message -// as canonical JSON so that it fits on a single line. -// It then runs the roomserver and waits for a number of messages to be written -// to the output topic. -// Once those messages have been written it runs the checkQueries function passing -// a api.RoomserverQueryAPI client. The caller can use this function to check the -// behaviour of the query API. -func testRoomserver(input []string, wantOutput []string, checkQueries func(api.RoomserverInternalAPI)) { - dir, err := ioutil.TempDir("", "room-server-test") - if err != nil { - panic(err) - } - - cfg, _, err := test.MakeConfig(dir, kafkaURI, testDatabase, "localhost", 10000) - if err != nil { - panic(err) - } - if err = test.WriteConfig(cfg, dir); err != nil { - panic(err) - } - - outputTopic := cfg.Global.Kafka.TopicFor(config.TopicOutputRoomEvent) - - err = exe.DeleteTopic(outputTopic) - if err != nil { - panic(err) - } - - if err = exe.CreateTopic(outputTopic); err != nil { - panic(err) - } - - if err = createDatabase(testDatabaseName); err != nil { - panic(err) - } - - cache, err := caching.NewInMemoryLRUCache(false) - if err != nil { - panic(err) - } - - doInput := func() { - fmt.Printf("Roomserver is ready to receive input, sending %d events\n", len(input)) - if err = writeToRoomServer(input, cfg.RoomServerURL()); err != nil { - panic(err) - } - } - - cmd := exec.Command(filepath.Join(filepath.Dir(os.Args[0]), "dendrite-room-server")) - - // Append the roomserver config to the existing environment. - // We append to the environment rather than replacing so that any additional - // postgres and golang environment variables such as PGHOST are passed to - // the roomserver process. - cmd.Stderr = os.Stderr - cmd.Args = []string{"dendrite-room-server", "--config", filepath.Join(dir, test.ConfigFile)} - - gotOutput, err := runAndReadFromTopic(cmd, cfg.RoomServerURL()+"/metrics", doInput, outputTopic, len(wantOutput), func() { - queryAPI, _ := inthttp.NewRoomserverClient("http://"+string(cfg.RoomServer.InternalAPI.Connect), &http.Client{Timeout: timeoutHTTP}, cache) - checkQueries(queryAPI) - }) - if err != nil { - panic(err) - } - - if len(wantOutput) != len(gotOutput) { - panic(fmt.Errorf("Wanted %d lines of output got %d lines", len(wantOutput), len(gotOutput))) - } - - for i := range wantOutput { - if !equalJSON(wantOutput[i], gotOutput[i]) { - panic(fmt.Errorf("Wanted %q at index %d got %q", wantOutput[i], i, gotOutput[i])) - } - } -} - -func equalJSON(a, b string) bool { - canonicalA, err := gomatrixserverlib.CanonicalJSON([]byte(a)) - if err != nil { - panic(err) - } - canonicalB, err := gomatrixserverlib.CanonicalJSON([]byte(b)) - if err != nil { - panic(err) - } - return string(canonicalA) == string(canonicalB) -} - -func main() { - fmt.Println("==TESTING==", os.Args[0]) - - input := []string{ - `{ - "auth_event_ids": [], - "kind": 1, - "event": { - "origin": "matrix.org", - "signatures": { - "matrix.org": { - "ed25519:auto": "3kXGwNtdj+zqEXlI8PWLiB76xtrQ7SxcvPuXAEVCTo+QPoBoUvLi1RkHs6O5mDz7UzIowK5bi1seAN4vOh0OBA" - } - }, - "origin_server_ts": 1463671337837, - "sender": "@richvdh:matrix.org", - "event_id": "$1463671337126266wrSBX:matrix.org", - "prev_events": [], - "state_key": "", - "content": {"creator": "@richvdh:matrix.org"}, - "depth": 1, - "prev_state": [], - "room_id": "!HCXfdvrfksxuYnIFiJ:matrix.org", - "auth_events": [], - "hashes": {"sha256": "Q05VLC8nztN2tguy+KnHxxhitI95wK9NelnsDaXRqeo"}, - "type": "m.room.create"} - }`, `{ - "auth_event_ids": ["$1463671337126266wrSBX:matrix.org"], - "kind": 2, - "state_event_ids": ["$1463671337126266wrSBX:matrix.org"], - "event": { - "origin": "matrix.org", - "signatures": { - "matrix.org": { - "ed25519:auto": "a2b3xXYVPPFeG1sHCU3hmZnAaKqZFgzGZozijRGblG5Y//ewRPAn1A2mCrI2UM5I+0zqr70cNpHgF8bmNFu4BA" - } - }, - "origin_server_ts": 1463671339844, - "sender": "@richvdh:matrix.org", - "event_id": "$1463671339126270PnVwC:matrix.org", - "prev_events": [[ - "$1463671337126266wrSBX:matrix.org", {"sha256": "h/VS07u8KlMwT3Ee8JhpkC7sa1WUs0Srgs+l3iBv6c0"} - ]], - "membership": "join", - "state_key": "@richvdh:matrix.org", - "content": { - "membership": "join", - "avatar_url": "mxc://matrix.org/ZafPzsxMJtLaSaJXloBEKiws", - "displayname": "richvdh" - }, - "depth": 2, - "prev_state": [], - "room_id": "!HCXfdvrfksxuYnIFiJ:matrix.org", - "auth_events": [[ - "$1463671337126266wrSBX:matrix.org", {"sha256": "h/VS07u8KlMwT3Ee8JhpkC7sa1WUs0Srgs+l3iBv6c0"} - ]], - "hashes": {"sha256": "t9t3sZV1Eu0P9Jyrs7pge6UTa1zuTbRdVxeUHnrQVH0"}, - "type": "m.room.member"}, - "has_state": true - }`, - } - - want := []string{ - `{"type":"new_room_event","new_room_event":{ - "event":{ - "auth_events":[[ - "$1463671337126266wrSBX:matrix.org",{"sha256":"h/VS07u8KlMwT3Ee8JhpkC7sa1WUs0Srgs+l3iBv6c0"} - ]], - "content":{ - "avatar_url":"mxc://matrix.org/ZafPzsxMJtLaSaJXloBEKiws", - "displayname":"richvdh", - "membership":"join" - }, - "depth": 2, - "event_id": "$1463671339126270PnVwC:matrix.org", - "hashes": {"sha256":"t9t3sZV1Eu0P9Jyrs7pge6UTa1zuTbRdVxeUHnrQVH0"}, - "membership": "join", - "origin": "matrix.org", - "origin_server_ts": 1463671339844, - "prev_events": [[ - "$1463671337126266wrSBX:matrix.org",{"sha256":"h/VS07u8KlMwT3Ee8JhpkC7sa1WUs0Srgs+l3iBv6c0"} - ]], - "prev_state":[], - "room_id":"!HCXfdvrfksxuYnIFiJ:matrix.org", - "sender":"@richvdh:matrix.org", - "signatures":{ - "matrix.org":{ - "ed25519:auto":"a2b3xXYVPPFeG1sHCU3hmZnAaKqZFgzGZozijRGblG5Y//ewRPAn1A2mCrI2UM5I+0zqr70cNpHgF8bmNFu4BA" - } - }, - "state_key":"@richvdh:matrix.org", - "type":"m.room.member" - }, - "state_before_removes_event_ids":["$1463671339126270PnVwC:matrix.org"], - "state_before_adds_event_ids":null, - "latest_event_ids":["$1463671339126270PnVwC:matrix.org"], - "adds_state_event_ids":["$1463671337126266wrSBX:matrix.org", "$1463671339126270PnVwC:matrix.org"], - "removes_state_event_ids":null, - "last_sent_event_id":"", - "send_as_server":"", - "transaction_id": null - }}`, - } - - testRoomserver(input, want, func(q api.RoomserverInternalAPI) { - var response api.QueryLatestEventsAndStateResponse - if err := q.QueryLatestEventsAndState( - context.Background(), - &api.QueryLatestEventsAndStateRequest{ - RoomID: "!HCXfdvrfksxuYnIFiJ:matrix.org", - StateToFetch: []gomatrixserverlib.StateKeyTuple{ - {EventType: "m.room.member", StateKey: "@richvdh:matrix.org"}, - }, - }, - &response, - ); err != nil { - panic(err) - } - if !response.RoomExists { - panic(fmt.Errorf(`Wanted room "!HCXfdvrfksxuYnIFiJ:matrix.org" to exist`)) - } - if len(response.LatestEvents) != 1 || response.LatestEvents[0].EventID != "$1463671339126270PnVwC:matrix.org" { - panic(fmt.Errorf(`Wanted "$1463671339126270PnVwC:matrix.org" to be the latest event got %#v`, response.LatestEvents)) - } - if len(response.StateEvents) != 1 || response.StateEvents[0].EventID() != "$1463671339126270PnVwC:matrix.org" { - panic(fmt.Errorf(`Wanted "$1463671339126270PnVwC:matrix.org" to be the state event got %#v`, response.StateEvents)) - } - }) - - fmt.Println("==PASSED==", os.Args[0]) -} diff --git a/cmd/syncserver-integration-tests/main.go b/cmd/syncserver-integration-tests/main.go deleted file mode 100644 index 332bde10..00000000 --- a/cmd/syncserver-integration-tests/main.go +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "path/filepath" - "time" - - "github.com/matrix-org/dendrite/internal/test" - "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/gomatrixserverlib" -) - -var ( - // Path to where kafka is installed. - kafkaDir = test.Defaulting(os.Getenv("KAFKA_DIR"), "kafka") - // The URI the kafka zookeeper is listening on. - zookeeperURI = test.Defaulting(os.Getenv("ZOOKEEPER_URI"), "localhost:2181") - // The URI the kafka server is listening on. - kafkaURI = test.Defaulting(os.Getenv("KAFKA_URIS"), "localhost:9092") - // The address the syncserver should listen on. - syncserverAddr = test.Defaulting(os.Getenv("SYNCSERVER_URI"), "localhost:9876") - // How long to wait for the syncserver to write the expected output messages. - // This needs to be high enough to account for the time it takes to create - // the postgres database tables which can take a while on travis. - timeoutString = test.Defaulting(os.Getenv("TIMEOUT"), "10s") - // The name of maintenance database to connect to in order to create the test database. - postgresDatabase = test.Defaulting(os.Getenv("POSTGRES_DATABASE"), "postgres") - // Postgres docker container name (for running psql). If not set, psql must be in PATH. - postgresContainerName = os.Getenv("POSTGRES_CONTAINER") - // The name of the test database to create. - testDatabaseName = test.Defaulting(os.Getenv("DATABASE_NAME"), "syncserver_test") - // The postgres connection config for connecting to the test database. - testDatabase = test.Defaulting(os.Getenv("DATABASE"), fmt.Sprintf("dbname=%s sslmode=disable binary_parameters=yes", testDatabaseName)) -) - -const inputTopic = "syncserverInput" -const clientTopic = "clientapiserverOutput" - -var exe = test.KafkaExecutor{ - ZookeeperURI: zookeeperURI, - KafkaDirectory: kafkaDir, - KafkaURI: kafkaURI, - // Send stdout and stderr to our stderr so that we see error messages from - // the kafka process. - OutputWriter: os.Stderr, -} - -var timeout time.Duration -var clientEventTestData []string - -func init() { - var err error - timeout, err = time.ParseDuration(timeoutString) - if err != nil { - panic(err) - } - - for _, s := range outputRoomEventTestData { - clientEventTestData = append(clientEventTestData, clientEventJSONForOutputRoomEvent(s)) - } -} - -func createTestUser(database, username, token string) error { - cmd := exec.Command( - filepath.Join(filepath.Dir(os.Args[0]), "create-account"), - "--database", database, - "--username", username, - "--token", token, - ) - - // Send stdout and stderr to our stderr so that we see error messages from - // the create-account process - cmd.Stdout = os.Stderr - cmd.Stderr = os.Stderr - return cmd.Run() -} - -// clientEventJSONForOutputRoomEvent parses the given output room event and extracts the 'Event' JSON. It is -// trimmed to the client format and then canonicalised and returned as a string. -// Panics if there are any problems. -func clientEventJSONForOutputRoomEvent(outputRoomEvent string) string { - var out api.OutputEvent - if err := json.Unmarshal([]byte(outputRoomEvent), &out); err != nil { - panic("failed to unmarshal output room event: " + err.Error()) - } - clientEvs := gomatrixserverlib.ToClientEvents([]*gomatrixserverlib.Event{ - out.NewRoomEvent.Event.Event, - }, gomatrixserverlib.FormatSync) - b, err := json.Marshal(clientEvs[0]) - if err != nil { - panic("failed to marshal client event as json: " + err.Error()) - } - jsonBytes, err := gomatrixserverlib.CanonicalJSON(b) - if err != nil { - panic("failed to turn event json into canonical json: " + err.Error()) - } - return string(jsonBytes) -} - -// startSyncServer creates the database and config file needed for the sync server to run and -// then starts the sync server. The Cmd being executed is returned. A channel is also returned, -// which will have any termination errors sent down it, followed immediately by the channel being closed. -func startSyncServer() (*exec.Cmd, chan error) { - - dir, err := ioutil.TempDir("", "syncapi-server-test") - if err != nil { - panic(err) - } - - cfg, _, err := test.MakeConfig(dir, kafkaURI, testDatabase, "localhost", 10000) - if err != nil { - panic(err) - } - // TODO use the address assigned by the config generator rather than clobbering. - cfg.Global.ServerName = "localhost" - cfg.SyncAPI.InternalAPI.Listen = config.HTTPAddress("http://" + syncserverAddr) - cfg.SyncAPI.InternalAPI.Connect = cfg.SyncAPI.InternalAPI.Listen - - if err := test.WriteConfig(cfg, dir); err != nil { - panic(err) - } - - serverArgs := []string{ - "--config", filepath.Join(dir, test.ConfigFile), - } - - databases := []string{ - testDatabaseName, - } - - test.InitDatabase( - postgresDatabase, - postgresContainerName, - databases, - ) - - if err := createTestUser(testDatabase, "alice", "@alice:localhost"); err != nil { - panic(err) - } - if err := createTestUser(testDatabase, "bob", "@bob:localhost"); err != nil { - panic(err) - } - if err := createTestUser(testDatabase, "charlie", "@charlie:localhost"); err != nil { - panic(err) - } - - cmd, cmdChan := test.CreateBackgroundCommand( - filepath.Join(filepath.Dir(os.Args[0]), "dendrite-sync-api-server"), - serverArgs, - ) - - return cmd, cmdChan -} - -// prepareKafka creates the topics which will be written to by the tests. -func prepareKafka() { - err := exe.DeleteTopic(inputTopic) - if err != nil { - panic(err) - } - - if err = exe.CreateTopic(inputTopic); err != nil { - panic(err) - } - - err = exe.DeleteTopic(clientTopic) - if err != nil { - panic(err) - } - - if err = exe.CreateTopic(clientTopic); err != nil { - panic(err) - } -} - -func testSyncServer(syncServerCmdChan chan error, userID, since, want string) { - fmt.Printf("==TESTING== testSyncServer(%s,%s)\n", userID, since) - sinceQuery := "" - if since != "" { - sinceQuery = "&since=" + since - } - req, err := http.NewRequest( - "GET", - "http://"+syncserverAddr+"/api/_matrix/client/r0/sync?timeout=100&access_token="+userID+sinceQuery, - nil, - ) - if err != nil { - panic(err) - } - testReq := &test.Request{ - Req: req, - WantedStatusCode: 200, - WantedBody: test.CanonicalJSONInput([]string{want})[0], - } - testReq.Run("sync-api", timeout, syncServerCmdChan) -} - -func writeToRoomServerLog(indexes ...int) { - var roomEvents []string - for _, i := range indexes { - roomEvents = append(roomEvents, outputRoomEventTestData[i]) - } - if err := exe.WriteToTopic(inputTopic, test.CanonicalJSONInput(roomEvents)); err != nil { - panic(err) - } -} - -// Runs a battery of sync server tests against test data in testdata.go -// testdata.go has a list of OutputRoomEvents which will be fed into the kafka log which the sync server will consume. -// The tests will pause at various points in this list to conduct tests on the /sync responses before continuing. -// For ease of understanding, the curl commands used to create the OutputRoomEvents are listed along with each write to kafka. -func main() { - fmt.Println("==TESTING==", os.Args[0]) - prepareKafka() - cmd, syncServerCmdChan := startSyncServer() - // ensure server is dead, only cleaning up so don't care about errors this returns. - defer cmd.Process.Kill() // nolint: errcheck - - // $ curl -XPOST -d '{}' "http://localhost:8009/_matrix/client/r0/createRoom?access_token=@alice:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/1?access_token=@alice:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world 2"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/2?access_token=@alice:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world 3"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - // $ curl -XPUT -d '{"name":"Custom Room Name"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - writeToRoomServerLog( - i0StateRoomCreate, i1StateAliceJoin, i2StatePowerLevels, i3StateJoinRules, i4StateHistoryVisibility, - i5AliceMsg, i6AliceMsg, i7AliceMsg, i8StateAliceRoomName, - ) - - // Make sure initial sync works TODO: prev_batch - testSyncServer(syncServerCmdChan, "@alice:localhost", "", `{ - "account_data": { - "events": [] - }, - "next_batch": "9", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": { - "!PjrbIMW2cIiaYF4t:localhost": { - "account_data": { - "events": [] - }, - "ephemeral": { - "events": [] - }, - "state": { - "events": [] - }, - "timeline": { - "events": [`+ - clientEventTestData[i0StateRoomCreate]+","+ - clientEventTestData[i1StateAliceJoin]+","+ - clientEventTestData[i2StatePowerLevels]+","+ - clientEventTestData[i3StateJoinRules]+","+ - clientEventTestData[i4StateHistoryVisibility]+","+ - clientEventTestData[i5AliceMsg]+","+ - clientEventTestData[i6AliceMsg]+","+ - clientEventTestData[i7AliceMsg]+","+ - clientEventTestData[i8StateAliceRoomName]+`], - "limited": true, - "prev_batch": "" - } - } - }, - "leave": {} - } - }`) - // Make sure alice's rooms don't leak to bob - testSyncServer(syncServerCmdChan, "@bob:localhost", "", `{ - "account_data": { - "events": [] - }, - "next_batch": "9", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": {}, - "leave": {} - } - }`) - // Make sure polling with an up-to-date token returns nothing new - testSyncServer(syncServerCmdChan, "@alice:localhost", "9", `{ - "account_data": { - "events": [] - }, - "next_batch": "9", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": {}, - "leave": {} - } - }`) - - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - writeToRoomServerLog(i9StateBobJoin) - - // Make sure alice sees it TODO: prev_batch - testSyncServer(syncServerCmdChan, "@alice:localhost", "9", `{ - "account_data": { - "events": [] - }, - "next_batch": "10", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": { - "!PjrbIMW2cIiaYF4t:localhost": { - "account_data": { - "events": [] - }, - "ephemeral": { - "events": [] - }, - "state": { - "events": [] - }, - "timeline": { - "limited": false, - "prev_batch": "", - "events": [`+clientEventTestData[i9StateBobJoin]+`] - } - } - }, - "leave": {} - } - }`) - - // Make sure bob sees the room AND all the current room state TODO: history visibility - testSyncServer(syncServerCmdChan, "@bob:localhost", "9", `{ - "account_data": { - "events": [] - }, - "next_batch": "10", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": { - "!PjrbIMW2cIiaYF4t:localhost": { - "account_data": { - "events": [] - }, - "ephemeral": { - "events": [] - }, - "state": { - "events": [`+ - clientEventTestData[i0StateRoomCreate]+","+ - clientEventTestData[i1StateAliceJoin]+","+ - clientEventTestData[i2StatePowerLevels]+","+ - clientEventTestData[i3StateJoinRules]+","+ - clientEventTestData[i4StateHistoryVisibility]+","+ - clientEventTestData[i8StateAliceRoomName]+`] - }, - "timeline": { - "limited": false, - "prev_batch": "", - "events": [`+ - clientEventTestData[i9StateBobJoin]+`] - } - } - }, - "leave": {} - } - }`) - - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello alice"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/1?access_token=@bob:localhost" - writeToRoomServerLog(i10BobMsg) - - // Make sure alice can see everything around the join point for bob TODO: prev_batch - testSyncServer(syncServerCmdChan, "@alice:localhost", "7", `{ - "account_data": { - "events": [] - }, - "next_batch": "11", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": { - "!PjrbIMW2cIiaYF4t:localhost": { - "account_data": { - "events": [] - }, - "ephemeral": { - "events": [] - }, - "state": { - "events": [] - }, - "timeline": { - "limited": false, - "prev_batch": "", - "events": [`+ - clientEventTestData[i7AliceMsg]+","+ - clientEventTestData[i8StateAliceRoomName]+","+ - clientEventTestData[i9StateBobJoin]+","+ - clientEventTestData[i10BobMsg]+`] - } - } - }, - "leave": {} - } - }`) - - // $ curl -XPUT -d '{"name":"A Different Custom Room Name"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello bob"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/2?access_token=@alice:localhost" - // $ curl -XPUT -d '{"membership":"invite"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@bob:localhost" - writeToRoomServerLog(i11StateAliceRoomName, i12AliceMsg, i13StateBobInviteCharlie) - - // Make sure charlie sees the invite both with and without a ?since= token - // TODO: Invite state should include the invite event and the room name. - charlieInviteData := `{ - "account_data": { - "events": [] - }, - "next_batch": "14", - "presence": { - "events": [] - }, - "rooms": { - "invite": { - "!PjrbIMW2cIiaYF4t:localhost": { - "invite_state": { - "events": [] - } - } - }, - "join": {}, - "leave": {} - } - }` - testSyncServer(syncServerCmdChan, "@charlie:localhost", "7", charlieInviteData) - testSyncServer(syncServerCmdChan, "@charlie:localhost", "", charlieInviteData) - - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@charlie:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"not charlie..."}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@alice:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"why did you kick charlie"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@bob:localhost" - writeToRoomServerLog(i14StateCharlieJoin, i15AliceMsg, i16StateAliceKickCharlie, i17BobMsg) - - // Check transitions to leave work - testSyncServer(syncServerCmdChan, "@charlie:localhost", "15", `{ - "account_data": { - "events": [] - }, - "next_batch": "18", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": {}, - "leave": { - "!PjrbIMW2cIiaYF4t:localhost": { - "state": { - "events": [] - }, - "timeline": { - "limited": false, - "prev_batch": "", - "events": [`+ - clientEventTestData[i15AliceMsg]+","+ - clientEventTestData[i16StateAliceKickCharlie]+`] - } - } - } - } - }`) - - // Test joining and leaving the same room in a single /sync request puts the room in the 'leave' section. - // TODO: Use an earlier since value to assert that the /sync response doesn't leak messages - // from before charlie was joined to the room. Currently it does leak because RecentEvents doesn't - // take membership into account. - testSyncServer(syncServerCmdChan, "@charlie:localhost", "14", `{ - "account_data": { - "events": [] - }, - "next_batch": "18", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": {}, - "leave": { - "!PjrbIMW2cIiaYF4t:localhost": { - "state": { - "events": [] - }, - "timeline": { - "limited": false, - "prev_batch": "", - "events": [`+ - clientEventTestData[i14StateCharlieJoin]+","+ - clientEventTestData[i15AliceMsg]+","+ - clientEventTestData[i16StateAliceKickCharlie]+`] - } - } - } - } - }`) - - // $ curl -XPUT -d '{"name":"No Charlies"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - writeToRoomServerLog(i18StateAliceRoomName) - - // Check that users don't see state changes in rooms after they have left - testSyncServer(syncServerCmdChan, "@charlie:localhost", "17", `{ - "account_data": { - "events": [] - }, - "next_batch": "19", - "presence": { - "events": [] - }, - "rooms": { - "invite": {}, - "join": {}, - "leave": {} - } - }`) - - // $ curl -XPUT -d '{"msgtype":"m.text","body":"whatever"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@bob:localhost" - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"im alone now"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - // $ curl -XPUT -d '{"membership":"invite"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@alice:localhost" - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"so alone"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - // $ curl -XPUT -d '{"name":"Everyone welcome"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@charlie:localhost" - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hiiiii"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@charlie:localhost" -} diff --git a/cmd/syncserver-integration-tests/testdata.go b/cmd/syncserver-integration-tests/testdata.go deleted file mode 100644 index 4ff5d1ee..00000000 --- a/cmd/syncserver-integration-tests/testdata.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 Vector Creations Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -// nolint: varcheck, deadcode, unused, megacheck -const ( - i0StateRoomCreate = iota - i1StateAliceJoin - i2StatePowerLevels - i3StateJoinRules - i4StateHistoryVisibility - i5AliceMsg - i6AliceMsg - i7AliceMsg - i8StateAliceRoomName - i9StateBobJoin - i10BobMsg - i11StateAliceRoomName - i12AliceMsg - i13StateBobInviteCharlie - i14StateCharlieJoin - i15AliceMsg - i16StateAliceKickCharlie - i17BobMsg - i18StateAliceRoomName - i19BobMsg - i20StateBobLeave - i21AliceMsg - i22StateAliceInviteBob - i23StateBobRejectInvite - i24AliceMsg - i25StateAliceRoomName - i26StateCharlieJoin - i27CharlieMsg -) - -var outputRoomEventTestData = []string{ - // $ curl -XPOST -d '{}' "http://localhost:8009/_matrix/client/r0/createRoom?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[],"content":{"creator":"@alice:localhost"},"depth":1,"event_id":"$xz0fUB8zNMTGFh1W:localhost","hashes":{"sha256":"KKkpxS8NoH0igBbL3J+nJ39MRlmA7QgW4BGL7Fv4ASI"},"origin":"localhost","origin_server_ts":1494411218382,"prev_events":[],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"uZG5Q/Hs2Z611gFlZPdwomomRJKf70xV2FQV+gLWM1XgzkLDRlRF3cBZc9y3CnHKnV/upTcXs7Op2/GmgD3UBw"}},"state_key":"","type":"m.room.create"},"latest_event_ids":["$xz0fUB8zNMTGFh1W:localhost"],"adds_state_event_ids":["$xz0fUB8zNMTGFh1W:localhost"],"last_sent_event_id":""}}`, - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}]],"content":{"membership":"join"},"depth":2,"event_id":"$QTen1vksfcRTpUCk:localhost","hashes":{"sha256":"tTukc9ab1fJfzgc5EMA/UD3swqfl/ic9Y9Zkt4fJo0Q"},"origin":"localhost","origin_server_ts":1494411218385,"prev_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"OPysDn/wT7yHeALXLTcEgR+iaKjv0p7VPuR/Mzvyg2IMAwPUjSOw8SQZlhSioWRtVPUp9VHbhIhJxQaPUg9yBQ"}},"state_key":"@alice:localhost","type":"m.room.member"},"latest_event_ids":["$QTen1vksfcRTpUCk:localhost"],"adds_state_event_ids":["$QTen1vksfcRTpUCk:localhost"],"last_sent_event_id":"$xz0fUB8zNMTGFh1W:localhost"}}`, - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}]],"content":{"ban":50,"events":{"m.room.avatar":50,"m.room.canonical_alias":50,"m.room.history_visibility":100,"m.room.name":50,"m.room.power_levels":100},"events_default":0,"invite":0,"kick":50,"redact":50,"state_default":50,"users":{"@alice:localhost":100},"users_default":0},"depth":3,"event_id":"$RWsxGlfPHAcijTgu:localhost","hashes":{"sha256":"ueZWiL/Q8bagRQGFktpnYJAJV6V6U3QKcUEmWYeyaaM"},"origin":"localhost","origin_server_ts":1494411218385,"prev_events":[["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"hZwWx3lyW61zMYmqLOxLTlfW2CnbjJQsZPLjZFa97TVG4ISz8CixMPsnVAIu5is29UCmiHyP8RvLecJjbLCtAQ"}},"state_key":"","type":"m.room.power_levels"},"latest_event_ids":["$RWsxGlfPHAcijTgu:localhost"],"adds_state_event_ids":["$RWsxGlfPHAcijTgu:localhost"],"last_sent_event_id":"$QTen1vksfcRTpUCk:localhost"}}`, - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}]],"content":{"join_rule":"public"},"depth":4,"event_id":"$2O2DpHB37CuwwJOe:localhost","hashes":{"sha256":"3P3HxAXI8gc094i020EoV/gissYiMVWv8+JAbrakM4E"},"origin":"localhost","origin_server_ts":1494411218386,"prev_events":[["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"L2yZoBbG/6TNsRHz+UtHY0SK4FgrdAYPR1l7RBWaNFbm+k/7kVhnoGlJ9yptpdLJjPMR2InqKXH8BBxRC83BCg"}},"state_key":"","type":"m.room.join_rules"},"latest_event_ids":["$2O2DpHB37CuwwJOe:localhost"],"adds_state_event_ids":["$2O2DpHB37CuwwJOe:localhost"],"last_sent_event_id":"$RWsxGlfPHAcijTgu:localhost"}}`, - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}]],"content":{"history_visibility":"joined"},"depth":5,"event_id":"$5LRiBskVCROnL5WY:localhost","hashes":{"sha256":"341alVufcKSVKLPr9WsJNTnW33QkBTn9eTfVWbyoa0o"},"origin":"localhost","origin_server_ts":1494411218387,"prev_events":[["$2O2DpHB37CuwwJOe:localhost",{"sha256":"ulaRD63dbCyolLTwvInIQpcrtU2c7ex/BHmhpLXAUoE"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"kRyt68cstwYgK8NtYzf0V5CnAbqUO47ixCCWYzRCi0WNstEwUw4XW1GHc8BllQsXwSj+nNv9g/66zZgG0DtxCA"}},"state_key":"","type":"m.room.history_visibility"},"latest_event_ids":["$5LRiBskVCROnL5WY:localhost"],"adds_state_event_ids":["$5LRiBskVCROnL5WY:localhost"],"last_sent_event_id":"$2O2DpHB37CuwwJOe:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/1?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"hello world","msgtype":"m.text"},"depth":0,"event_id":"$Z8ZJik7ghwzSYTH9:localhost","hashes":{"sha256":"ahN1T5aiSZCzllf0pqNWJkF+x2h2S3kic+40pQ1X6BE"},"origin":"localhost","origin_server_ts":1494411339207,"prev_events":[["$5LRiBskVCROnL5WY:localhost",{"sha256":"3jULNC9b9Q0AhvnDQqpjhbtYwmkioHzPzdTJZvn8vOI"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"ylEpahRwEfGpqk+UCv0IF8YAxmut7w7udgHy3sVDfdJhs/4uJ6EkFEsKLknpXRc1vTIy1etKCBQ63QbCmRC2Bw"}},"type":"m.room.message"},"latest_event_ids":["$Z8ZJik7ghwzSYTH9:localhost"],"last_sent_event_id":"$5LRiBskVCROnL5WY:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world 2"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/2?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"hello world 2","msgtype":"m.text"},"depth":0,"event_id":"$8382Ah682eL4hxjN:localhost","hashes":{"sha256":"hQElDGSYc6KOdylrbMMm3+LlvUiCKo6S9G9n58/qtns"},"origin":"localhost","origin_server_ts":1494411380282,"prev_events":[["$Z8ZJik7ghwzSYTH9:localhost",{"sha256":"FBDwP+2FeqDENe7AEa3iAFAVKl1/IVq43mCH0uPRn90"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"LFXi6jTG7qn9xzi4rhIiHbkLD+4AZ9Yg7UTS2gqm1gt2lXQsgTYH1wE4Fol2fq4lvGlQVpxhtEr2huAYSbT7DA"}},"type":"m.room.message"},"latest_event_ids":["$8382Ah682eL4hxjN:localhost"],"last_sent_event_id":"$Z8ZJik7ghwzSYTH9:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello world 3"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"hello world 3","msgtype":"m.text"},"depth":0,"event_id":"$17SfHsvSeTQthSWF:localhost","hashes":{"sha256":"eS6VFQI0l2U8rA8U17jgSHr9lQ73SNSnlnZu+HD0IjE"},"origin":"localhost","origin_server_ts":1494411396560,"prev_events":[["$8382Ah682eL4hxjN:localhost",{"sha256":"c6I/PUY7WnvxQ+oUEp/w2HEEuD3g8Vq7QwPUOSUjuc8"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"dvu9bSHZmX+yZoEqHioK7YDMtLH9kol0DdFqc5aHsbhZe/fKRZpfJMrlf1iXQdXSCMhikvnboPAXN3guiZCUBQ"}},"type":"m.room.message"},"latest_event_ids":["$17SfHsvSeTQthSWF:localhost"],"last_sent_event_id":"$8382Ah682eL4hxjN:localhost"}}`, - // $ curl -XPUT -d '{"name":"Custom Room Name"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"name":"Custom Room Name"},"depth":0,"event_id":"$j7KtuOzM0K15h3Kr:localhost","hashes":{"sha256":"QIKj5Klr50ugll4EjaNUATJmrru4CDp6TvGPv0v15bo"},"origin":"localhost","origin_server_ts":1494411482625,"prev_events":[["$17SfHsvSeTQthSWF:localhost",{"sha256":"iMTefewJ4W5sKQy7osQv4ilJAi7X0NsK791kqEUmYX0"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"WU7lwSWUAk7bsyDnBs128PyXxPZZoD1sN4AiDcvk+W1mDezJbFvWHDWymclxWESlP7TDrFTZEumRWGGCakjyAg"}},"state_key":"","type":"m.room.name"},"latest_event_ids":["$j7KtuOzM0K15h3Kr:localhost"],"adds_state_event_ids":["$j7KtuOzM0K15h3Kr:localhost"],"last_sent_event_id":"$17SfHsvSeTQthSWF:localhost"}}`, - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$2O2DpHB37CuwwJOe:localhost",{"sha256":"ulaRD63dbCyolLTwvInIQpcrtU2c7ex/BHmhpLXAUoE"}]],"content":{"membership":"join"},"depth":0,"event_id":"$wPepDhIla765Odre:localhost","hashes":{"sha256":"KeKqWLvM+LTvyFbwx6y3Y4W5Pj6nBSFUQ6jpkSf1oTE"},"origin":"localhost","origin_server_ts":1494411534290,"prev_events":[["$j7KtuOzM0K15h3Kr:localhost",{"sha256":"oDrWG5/sy1Ea3hYDOSJZRuGKCcjaHQlDYPDn2gB0/L0"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"oVtvjZbWFe+iJhoDvLcQKnFpSYQ94dOodM4gGsx26P6fs2sFJissYwSIqpoxlElCJnmBAgy5iv4JK/5x21R2CQ"}},"state_key":"@bob:localhost","type":"m.room.member"},"latest_event_ids":["$wPepDhIla765Odre:localhost"],"adds_state_event_ids":["$wPepDhIla765Odre:localhost"],"last_sent_event_id":"$j7KtuOzM0K15h3Kr:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello alice"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/1?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"content":{"body":"hello alice","msgtype":"m.text"},"depth":0,"event_id":"$RHNjeYUvXVZfb93t:localhost","hashes":{"sha256":"Ic1QLxTWFrWt1o31DS93ftrNHkunf4O6ubFvdD4ydNI"},"origin":"localhost","origin_server_ts":1494411593196,"prev_events":[["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"8BHHkiThWwiIZbXCegRjIKNVGIa2kqrZW8VuL7nASfJBORhZ9R9p34UsmhsxVwTs/2/dX7M2ogMB28gIGdLQCg"}},"type":"m.room.message"},"latest_event_ids":["$RHNjeYUvXVZfb93t:localhost"],"last_sent_event_id":"$wPepDhIla765Odre:localhost"}}`, - // $ curl -XPUT -d '{"name":"A Different Custom Room Name"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"name":"A Different Custom Room Name"},"depth":0,"event_id":"$1xoUuqOFjFFJgwA5:localhost","hashes":{"sha256":"2pNnLhoHxNeSUpqxrd3c0kZUA4I+cdWZgYcJ8V3e2tk"},"origin":"localhost","origin_server_ts":1494411643348,"prev_events":[["$RHNjeYUvXVZfb93t:localhost",{"sha256":"LqFmTIzULgUDSf5xM3REObvnsRGLQliWBUf1hEDT4+w"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"gsY4B6TIBdVvLyFAaXw0xez9N5/Cn/ZaJ4z+j9gJU/ZR8j1t3OYlcVQN6uln9JwEU1k20AsGnIqvOaayd+bfCg"}},"state_key":"","type":"m.room.name"},"latest_event_ids":["$1xoUuqOFjFFJgwA5:localhost"],"adds_state_event_ids":["$1xoUuqOFjFFJgwA5:localhost"],"removes_state_event_ids":["$j7KtuOzM0K15h3Kr:localhost"],"last_sent_event_id":"$RHNjeYUvXVZfb93t:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hello bob"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/2?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"hello bob","msgtype":"m.text"},"depth":0,"event_id":"$4NBTdIwDxq5fDGpv:localhost","hashes":{"sha256":"msCIESAya8kD7nLCopxkEqrgVuGfrlr9YBIADH5czTA"},"origin":"localhost","origin_server_ts":1494411674630,"prev_events":[["$1xoUuqOFjFFJgwA5:localhost",{"sha256":"ZXj+kY6sqQpf5vsNqvCMSvNoXXKDKxRE4R7+gZD9Tkk"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"bZRT3NxVlfBWw1PxSlKlgfnJixG+NI5H9QmUK2AjECg+l887BZJNCvAK0eD27N8e9V+c2glyXWYje2wexP2CBw"}},"type":"m.room.message"},"latest_event_ids":["$4NBTdIwDxq5fDGpv:localhost"],"last_sent_event_id":"$1xoUuqOFjFFJgwA5:localhost"}}`, - // $ curl -XPUT -d '{"membership":"invite"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"content":{"membership":"invite"},"depth":0,"event_id":"$zzLHVlHIWPrnE7DI:localhost","hashes":{"sha256":"LKk7tnYJAHsyffbi9CzfdP+TU4KQ5g6YTgYGKjJ7NxU"},"origin":"localhost","origin_server_ts":1494411709192,"prev_events":[["$4NBTdIwDxq5fDGpv:localhost",{"sha256":"EpqmxEoJP93Zb2Nt2fS95SJWTqqIutHm/Ne8OHqp6Ps"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"GdUzkC+7YKl1XDi7kYuD39yi2L/+nv+YrecIQHS+0BLDQqnEj+iRXfNBuZfTk6lUBCJCHXZlk7MnEIjvWDlZCg"}},"state_key":"@charlie:localhost","type":"m.room.member"},"latest_event_ids":["$zzLHVlHIWPrnE7DI:localhost"],"adds_state_event_ids":["$zzLHVlHIWPrnE7DI:localhost"],"last_sent_event_id":"$4NBTdIwDxq5fDGpv:localhost"}}`, - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@charlie:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$2O2DpHB37CuwwJOe:localhost",{"sha256":"ulaRD63dbCyolLTwvInIQpcrtU2c7ex/BHmhpLXAUoE"}],["$zzLHVlHIWPrnE7DI:localhost",{"sha256":"Jw28x9W+GoZYw7sEynsi1fcRzqRQiLddolOa/p26PV0"}]],"content":{"membership":"join"},"unsigned":{"prev_content":{"membership":"invite"},"prev_sender":"@bob:localhost","replaces_state":"$zzLHVlHIWPrnE7DI:localhost"},"depth":0,"event_id":"$uJVKyzZi8ZX0kOd9:localhost","hashes":{"sha256":"9ZZs/Cg0ewpBiCB6iFXXYlmW8koFiesCNGFrOLDTolE"},"origin":"localhost","origin_server_ts":1494411745015,"prev_events":[["$zzLHVlHIWPrnE7DI:localhost",{"sha256":"Jw28x9W+GoZYw7sEynsi1fcRzqRQiLddolOa/p26PV0"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@charlie:localhost","signatures":{"localhost":{"ed25519:something":"+TM0gFPM/M3Ji2BjYuTUTgDyCOWlOq8aTMCxLg7EBvS62yPxJ558f13OWWTczUO5aRAt+PvXsMVM/bp8u6c8DQ"}},"state_key":"@charlie:localhost","type":"m.room.member"},"latest_event_ids":["$uJVKyzZi8ZX0kOd9:localhost"],"adds_state_event_ids":["$uJVKyzZi8ZX0kOd9:localhost"],"removes_state_event_ids":["$zzLHVlHIWPrnE7DI:localhost"],"last_sent_event_id":"$zzLHVlHIWPrnE7DI:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"not charlie..."}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"not charlie...","msgtype":"m.text"},"depth":0,"event_id":"$Ixfn5WT9ocWTYxfy:localhost","hashes":{"sha256":"hRChdyMQ3AY4jvrPpI8PEX6Taux83Qo5hdSeHlhPxGo"},"origin":"localhost","origin_server_ts":1494411792737,"prev_events":[["$uJVKyzZi8ZX0kOd9:localhost",{"sha256":"BtesLFnHZOREQCeilFM+xvDU/Wdj+nyHMw7IGTh/9gU"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"LC/Zqwu/XdqjmLdTOp/NQaFaE0niSAGgEpa39gCxsnsqEX80P7P5WDn/Kzx6rjWTnhIszrLsnoycqkXQT0Z4DQ"}},"type":"m.room.message"},"latest_event_ids":["$Ixfn5WT9ocWTYxfy:localhost"],"last_sent_event_id":"$uJVKyzZi8ZX0kOd9:localhost"}}`, - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$uJVKyzZi8ZX0kOd9:localhost",{"sha256":"BtesLFnHZOREQCeilFM+xvDU/Wdj+nyHMw7IGTh/9gU"}]],"content":{"membership":"leave"},"unsigned":{"prev_content":{"membership":"join"},"prev_sender":"@charlie:localhost","replaces_state":"$uJVKyzZi8ZX0kOd9:localhost"},"depth":0,"event_id":"$om1F4AI8tCYlHUSp:localhost","hashes":{"sha256":"7JVI0uCxSUyEqDJ+o36/zUIlIZkXVK/R6wkrZGvQXDE"},"origin":"localhost","origin_server_ts":1494411855278,"prev_events":[["$Ixfn5WT9ocWTYxfy:localhost",{"sha256":"hOoPIDQFvvNqQJzA5ggjoQi4v1BOELnhnmwU4UArDOY"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"3sxoDLUPnKuDJgFgS3C647BbiXrozxhhxrZOlFP3KgJKzBYv/ht+Jd2V2iSZOvsv94wgRBf0A/lEcJRIqeLgDA"}},"state_key":"@charlie:localhost","type":"m.room.member"},"latest_event_ids":["$om1F4AI8tCYlHUSp:localhost"],"adds_state_event_ids":["$om1F4AI8tCYlHUSp:localhost"],"removes_state_event_ids":["$uJVKyzZi8ZX0kOd9:localhost"],"last_sent_event_id":"$Ixfn5WT9ocWTYxfy:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"why did you kick charlie"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"content":{"body":"why did you kick charlie","msgtype":"m.text"},"depth":0,"event_id":"$hgao5gTmr3r9TtK2:localhost","hashes":{"sha256":"Aa2ZCrvwjX5xhvkVqIOFUeEGqrnrQZjjNFiZRybjsPY"},"origin":"localhost","origin_server_ts":1494411912809,"prev_events":[["$om1F4AI8tCYlHUSp:localhost",{"sha256":"yVs+CW7AiJrJOYouL8xPIBrtIHAhnbxaegna8MxeCto"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"sGkpbEXGsvAuCvE3wb5E9H5fjCVKpRdWNt6csj1bCB9Fmg4Rg4mvj3TAJ+91DjO8IPsgSxDKdqqRYF0OtcynBA"}},"type":"m.room.message"},"latest_event_ids":["$hgao5gTmr3r9TtK2:localhost"],"last_sent_event_id":"$om1F4AI8tCYlHUSp:localhost"}}`, - // $ curl -XPUT -d '{"name":"No Charlies"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"name":"No Charlies"},"depth":0,"event_id":"$CY4XDoxjbns3a4Pc:localhost","hashes":{"sha256":"chk72pVkp3AGR2FtdC0mORBWS1b9ePnRN4WK3BP0BiI"},"origin":"localhost","origin_server_ts":1494411959114,"prev_events":[["$hgao5gTmr3r9TtK2:localhost",{"sha256":"/4/OG4Q2YalIeBtN76BEPIieBKA/3UFshR9T+WJip4o"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"mapvA3KJYgw5FmzJMhSFa/+JSuNyv2eKAkiGomAeBB7LQ1e9nK9XhW/Fp7a5Z2Sy2ENwHyd3ij7FEGiLOnSIAw"}},"state_key":"","type":"m.room.name"},"latest_event_ids":["$CY4XDoxjbns3a4Pc:localhost"],"adds_state_event_ids":["$CY4XDoxjbns3a4Pc:localhost"],"removes_state_event_ids":["$1xoUuqOFjFFJgwA5:localhost"],"last_sent_event_id":"$hgao5gTmr3r9TtK2:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"whatever"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"content":{"body":"whatever","msgtype":"m.text"},"depth":0,"event_id":"$pl8VBHRPYDmsnDh4:localhost","hashes":{"sha256":"FYqY9+/cepwIxxjfFV3AjOFBXkTlyEI2jep87dUc+SU"},"origin":"localhost","origin_server_ts":1494411988548,"prev_events":[["$CY4XDoxjbns3a4Pc:localhost",{"sha256":"hCoV63fp8eiquVdEefsOqJtLmJhw4wTlRv+wNTS20Ac"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"sQKwRzE59eZyb8rDySo/pVwZXBh0nA5zx+kjEyXglxIQrTre+8Gj3R7Prni+RE3Dq7oWfKYV7QklTLURAaSICQ"}},"type":"m.room.message"},"latest_event_ids":["$pl8VBHRPYDmsnDh4:localhost"],"last_sent_event_id":"$CY4XDoxjbns3a4Pc:localhost"}}`, - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$wPepDhIla765Odre:localhost",{"sha256":"GqUhRiAkRvPrNBDyUxj+emRfK2P8j6iWtvsXDOUltiI"}]],"content":{"membership":"leave"},"depth":0,"event_id":"$acCW4IgnBo8YD3jw:localhost","hashes":{"sha256":"porP+E2yftBGjfS381+WpZeDM9gZHsM3UydlBcRKBLw"},"origin":"localhost","origin_server_ts":1494412037042,"prev_events":[["$pl8VBHRPYDmsnDh4:localhost",{"sha256":"b+qQ380JDFq7quVU9EbIJ2sbpUKM1LAUNX0ZZUoVMZw"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"kxbjTIC0/UR4cOYUAOTNiUc0SSVIF4BY6Rq6IEgYJemq4jcU2fYqum4mFxIQTDKKXMSRHEoNPDmYMFIJwkrsCg"}},"state_key":"@bob:localhost","type":"m.room.member"},"latest_event_ids":["$acCW4IgnBo8YD3jw:localhost"],"adds_state_event_ids":["$acCW4IgnBo8YD3jw:localhost"],"removes_state_event_ids":["$wPepDhIla765Odre:localhost"],"last_sent_event_id":"$pl8VBHRPYDmsnDh4:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"im alone now"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"im alone now","msgtype":"m.text"},"depth":0,"event_id":"$nYdEXrvTDeb7DfkC:localhost","hashes":{"sha256":"qibC5NmlJpSRMBWSWxy1pv73FXymhPDXQFMmGosfsV0"},"origin":"localhost","origin_server_ts":1494412084668,"prev_events":[["$acCW4IgnBo8YD3jw:localhost",{"sha256":"8h3uXoE6pnI9iLnXI6493qJ0HeuRQfenRIu9PcgH72g"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"EHRoZznhXywhYeIn83o4FSFm3No/aOdLQPHQ68YGtNgESWwpuWLkkGVjoISjz3QgXQ06Fl3cHt7nlTaAHpCNAg"}},"type":"m.room.message"},"latest_event_ids":["$nYdEXrvTDeb7DfkC:localhost"],"last_sent_event_id":"$acCW4IgnBo8YD3jw:localhost"}}`, - // $ curl -XPUT -d '{"membership":"invite"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$acCW4IgnBo8YD3jw:localhost",{"sha256":"8h3uXoE6pnI9iLnXI6493qJ0HeuRQfenRIu9PcgH72g"}]],"content":{"membership":"invite"},"depth":0,"event_id":"$gKNfcXLlWvs2cFad:localhost","hashes":{"sha256":"iYDOUjYkaGSFbVp7TRVFvGJyGMEuBHMQrJ9XqwhzmPI"},"origin":"localhost","origin_server_ts":1494412135845,"prev_events":[["$nYdEXrvTDeb7DfkC:localhost",{"sha256":"83T5Q3+nDvtS0oJTEhHxIw02twBDa1A7QR2bHtnxv1Y"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"ofw009aMJMqVjww9eDXgeTjOQqSlJl/GN/AAb+6mZAPcUI8aVgRlXOSESfhu1ONEuV/yNUycxNXWfMwuvoWsDg"}},"state_key":"@bob:localhost","type":"m.room.member"},"latest_event_ids":["$gKNfcXLlWvs2cFad:localhost"],"adds_state_event_ids":["$gKNfcXLlWvs2cFad:localhost"],"removes_state_event_ids":["$acCW4IgnBo8YD3jw:localhost"],"last_sent_event_id":"$nYdEXrvTDeb7DfkC:localhost"}}`, - // $ curl -XPUT -d '{"membership":"leave"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@bob:localhost?access_token=@bob:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$gKNfcXLlWvs2cFad:localhost",{"sha256":"/TYIY+L9qjg516Bzl8sadu+Np21KkxE4KdPXALeJ9eE"}]],"content":{"membership":"leave"},"depth":0,"event_id":"$B2q9Tepb6Xc1Rku0:localhost","hashes":{"sha256":"RbHTVdceAEfTALQDZdGrOmakKeTYnChaKjlVuoNUdSY"},"origin":"localhost","origin_server_ts":1494412187614,"prev_events":[["$gKNfcXLlWvs2cFad:localhost",{"sha256":"/TYIY+L9qjg516Bzl8sadu+Np21KkxE4KdPXALeJ9eE"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@bob:localhost","signatures":{"localhost":{"ed25519:something":"dNtUL86j2zUe5+DkfOkil5VujvFZg4FeTjbtcpeF+3E4SUChCAG3lyR6YOAIYBnjtD0/kqT7OcP3pM6vMEp1Aw"}},"state_key":"@bob:localhost","type":"m.room.member"},"latest_event_ids":["$B2q9Tepb6Xc1Rku0:localhost"],"adds_state_event_ids":["$B2q9Tepb6Xc1Rku0:localhost"],"removes_state_event_ids":["$gKNfcXLlWvs2cFad:localhost"],"last_sent_event_id":"$gKNfcXLlWvs2cFad:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"so alone"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"body":"so alone","msgtype":"m.text"},"depth":0,"event_id":"$W1nrYHQIbCTTSJOV:localhost","hashes":{"sha256":"uUKSa4U1coDoT3LUcNF25dt+UpUa2pLXzRJ3ljgxXZs"},"origin":"localhost","origin_server_ts":1494412229742,"prev_events":[["$B2q9Tepb6Xc1Rku0:localhost",{"sha256":"0CLru7nGPgyF9AWlZnarCElscSVrXl2MMY2atrz80Uc"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"YlBJyDnE34UhaCB9hirQN5OySfTDoqiBDnNvxomXjU94z4a8g2CLWKjApwd/q/j4HamCUtjgkjJ2um6hNjsVBA"}},"type":"m.room.message"},"latest_event_ids":["$W1nrYHQIbCTTSJOV:localhost"],"last_sent_event_id":"$B2q9Tepb6Xc1Rku0:localhost"}}`, - // $ curl -XPUT -d '{"name":"Everyone welcome"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.name?access_token=@alice:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$QTen1vksfcRTpUCk:localhost",{"sha256":"znwhbYzdueh0grYkUX4jgXmP9AjKphzyesMZWMiF4IY"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}]],"content":{"name":"Everyone welcome"},"depth":0,"event_id":"$nLzxoBC4A0QRvJ1k:localhost","hashes":{"sha256":"PExCybjaMW1TfgFr57MdIRYJ642FY2jnrdW/tpPOf1Y"},"origin":"localhost","origin_server_ts":1494412294551,"prev_events":[["$W1nrYHQIbCTTSJOV:localhost",{"sha256":"HXk/ACcsiaZ/z1f2aZSIhJF8Ih3BWeh1vp+cV/fwoE0"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@alice:localhost","signatures":{"localhost":{"ed25519:something":"RK09L8sQv78y69PNbOLaX8asq5kp51mbqUuct5gd7ZNmaHKnVds6ew06QEn+gHSDAxqQo2tpcfoajp+yMj1HBw"}},"state_key":"","type":"m.room.name"},"latest_event_ids":["$nLzxoBC4A0QRvJ1k:localhost"],"adds_state_event_ids":["$nLzxoBC4A0QRvJ1k:localhost"],"removes_state_event_ids":["$CY4XDoxjbns3a4Pc:localhost"],"last_sent_event_id":"$W1nrYHQIbCTTSJOV:localhost"}}`, - // $ curl -XPUT -d '{"membership":"join"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/state/m.room.member/@charlie:localhost?access_token=@charlie:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$2O2DpHB37CuwwJOe:localhost",{"sha256":"ulaRD63dbCyolLTwvInIQpcrtU2c7ex/BHmhpLXAUoE"}],["$om1F4AI8tCYlHUSp:localhost",{"sha256":"yVs+CW7AiJrJOYouL8xPIBrtIHAhnbxaegna8MxeCto"}]],"content":{"membership":"join"},"depth":0,"event_id":"$Zo6P8r9bczF6kctV:localhost","hashes":{"sha256":"R3J2iUWnGxVdmly8ah+Dgb5VbJ2i/e8BLaWM0z9eZKU"},"origin":"localhost","origin_server_ts":1494412338689,"prev_events":[["$nLzxoBC4A0QRvJ1k:localhost",{"sha256":"TDcFaArAXpxIJ1noSubcFqkLXiQTrc1Dw1+kgCtx3XY"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@charlie:localhost","signatures":{"localhost":{"ed25519:something":"tVnjLVoJ9SLlMQIJSK/6zANWaEu8tVVkx3AEJiC3y5JmhPORb3PyG8eE+e/9hC4aJSQL8LGLaJNWXukMpb2SBg"}},"state_key":"@charlie:localhost","type":"m.room.member"},"latest_event_ids":["$Zo6P8r9bczF6kctV:localhost"],"adds_state_event_ids":["$Zo6P8r9bczF6kctV:localhost"],"removes_state_event_ids":["$om1F4AI8tCYlHUSp:localhost"],"last_sent_event_id":"$nLzxoBC4A0QRvJ1k:localhost"}}`, - // $ curl -XPUT -d '{"msgtype":"m.text","body":"hiiiii"}' "http://localhost:8009/_matrix/client/r0/rooms/%21PjrbIMW2cIiaYF4t:localhost/send/m.room.message/3?access_token=@charlie:localhost" - `{"type":"new_room_event","new_room_event":{"event":{"auth_events":[["$xz0fUB8zNMTGFh1W:localhost",{"sha256":"F4tTLtltC6f2XKeXq4ZKpMZ5EpditaW+RYQSnYzq3lI"}],["$RWsxGlfPHAcijTgu:localhost",{"sha256":"1zc+86U9vLK1BvTJbeLuYpw9dZqvX2fr8rc3pOF69f8"}],["$Zo6P8r9bczF6kctV:localhost",{"sha256":"mnjt3WTYqwtuyl2Fca+0cgm6moHaNL+W9BqRJTQzdEY"}]],"content":{"body":"hiiiii","msgtype":"m.text"},"depth":0,"event_id":"$YAEvK8u2zkTsjf5P:localhost","hashes":{"sha256":"6hKy61h1tuHjYdfpq2MnaPtGEBAZOUz8FLTtxLwjK5A"},"origin":"localhost","origin_server_ts":1494412375465,"prev_events":[["$Zo6P8r9bczF6kctV:localhost",{"sha256":"mnjt3WTYqwtuyl2Fca+0cgm6moHaNL+W9BqRJTQzdEY"}]],"room_id":"!PjrbIMW2cIiaYF4t:localhost","sender":"@charlie:localhost","signatures":{"localhost":{"ed25519:something":"BsSLaMM5U/YkyvBZ00J/+si9My+wAJZOcBhBeato0oHayiag7FW77ZpSTfADazPdNH62kjB0sdP9CN6vQA7yDg"}},"type":"m.room.message"},"latest_event_ids":["$YAEvK8u2zkTsjf5P:localhost"],"last_sent_event_id":"$Zo6P8r9bczF6kctV:localhost"}}`, -}