mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-07 23:13:11 -06:00
cmd/mediaapi-integration-tests: Add foundation for testing
This commit is contained in:
parent
2d202cec07
commit
85fcef2968
|
|
@ -15,6 +15,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
|
@ -36,27 +37,29 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
bindAddr = os.Getenv("BIND_ADDRESS")
|
||||
bindAddr = flag.String("listen", "", "The port to listen on.")
|
||||
dataSource = os.Getenv("DATABASE")
|
||||
logDir = os.Getenv("LOG_DIR")
|
||||
serverName = os.Getenv("SERVER_NAME")
|
||||
basePath = os.Getenv("BASE_PATH")
|
||||
// Note: if the MAX_FILE_SIZE_BYTES is set to 0, it will be unlimited
|
||||
maxFileSizeBytesString = os.Getenv("MAX_FILE_SIZE_BYTES")
|
||||
configPath = os.Getenv("CONFIG_PATH")
|
||||
configPath = flag.String("config", "", "The path to the config file. For more information, see the config file in this repository.")
|
||||
)
|
||||
|
||||
func main() {
|
||||
common.SetupLogging(logDir)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"BIND_ADDRESS": bindAddr,
|
||||
"listen": *bindAddr,
|
||||
"DATABASE": dataSource,
|
||||
"LOG_DIR": logDir,
|
||||
"SERVER_NAME": serverName,
|
||||
"BASE_PATH": basePath,
|
||||
"MAX_FILE_SIZE_BYTES": maxFileSizeBytesString,
|
||||
"CONFIG_PATH": configPath,
|
||||
"config": *configPath,
|
||||
}).Info("Loading configuration based on config file and environment variables")
|
||||
|
||||
cfg, err := configureServer()
|
||||
|
|
@ -64,15 +67,10 @@ func main() {
|
|||
log.WithError(err).Fatal("Invalid configuration")
|
||||
}
|
||||
|
||||
db, err := storage.Open(cfg.DataSource)
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to open database")
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"BIND_ADDRESS": bindAddr,
|
||||
"listen": *bindAddr,
|
||||
"LOG_DIR": logDir,
|
||||
"CONFIG_PATH": configPath,
|
||||
"CONFIG_PATH": *configPath,
|
||||
"ServerName": cfg.ServerName,
|
||||
"AbsBasePath": cfg.AbsBasePath,
|
||||
"MaxFileSizeBytes": *cfg.MaxFileSizeBytes,
|
||||
|
|
@ -82,13 +80,21 @@ func main() {
|
|||
"ThumbnailSizes": cfg.ThumbnailSizes,
|
||||
}).Info("Starting mediaapi server with configuration")
|
||||
|
||||
db, err := storage.Open(cfg.DataSource)
|
||||
if err != nil {
|
||||
log.WithError(err).Panic("Failed to open database")
|
||||
}
|
||||
|
||||
routing.Setup(http.DefaultServeMux, http.DefaultClient, cfg, db)
|
||||
log.Fatal(http.ListenAndServe(bindAddr, nil))
|
||||
log.Fatal(http.ListenAndServe(*bindAddr, nil))
|
||||
}
|
||||
|
||||
// configureServer loads configuration from a yaml file and overrides with environment variables
|
||||
func configureServer() (*config.MediaAPI, error) {
|
||||
cfg, err := loadConfig(configPath)
|
||||
if *configPath == "" {
|
||||
log.Fatal("--config must be supplied")
|
||||
}
|
||||
cfg, err := loadConfig(*configPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("Invalid config file")
|
||||
}
|
||||
|
|
@ -172,14 +178,14 @@ func applyOverrides(cfg *config.MediaAPI) {
|
|||
if cfg.MaxThumbnailGenerators == 0 {
|
||||
log.WithField(
|
||||
"max_thumbnail_generators", cfg.MaxThumbnailGenerators,
|
||||
).Info("Using default max_thumbnail_generators")
|
||||
).Info("Using default max_thumbnail_generators value of 10")
|
||||
cfg.MaxThumbnailGenerators = 10
|
||||
}
|
||||
}
|
||||
|
||||
func validateConfig(cfg *config.MediaAPI) error {
|
||||
if bindAddr == "" {
|
||||
return fmt.Errorf("no BIND_ADDRESS environment variable found")
|
||||
if *bindAddr == "" {
|
||||
log.Fatal("--listen must be supplied")
|
||||
}
|
||||
|
||||
absBasePath, err := getAbsolutePath(cfg.BasePath)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
* functional
|
||||
* upload
|
||||
* normal case
|
||||
* file too large
|
||||
* 0-byte file?
|
||||
* invalid filename
|
||||
* invalid content-type
|
||||
* download
|
||||
* invalid origin
|
||||
* invalid media id
|
||||
* local file
|
||||
* existing
|
||||
* non-existing
|
||||
* remote file
|
||||
* existing
|
||||
* non-existing
|
||||
* thumbnail
|
||||
* original file formats
|
||||
* JPEG
|
||||
* GIF
|
||||
* PNG
|
||||
* BMP
|
||||
* SVG
|
||||
* PDF
|
||||
* local file
|
||||
* existing
|
||||
* non-existing
|
||||
* remote file
|
||||
* existing
|
||||
* non-existing
|
||||
* cache
|
||||
* cold
|
||||
* hot
|
||||
* pre-generation according to configuration
|
||||
* manual verification + hash check for regressions?
|
||||
* dynamic generation
|
||||
* cold cache
|
||||
* hot cache
|
||||
* larger than original
|
||||
* limit on dimensions?
|
||||
* 0x0
|
||||
* scale
|
||||
* crop
|
||||
* load
|
||||
* 100 parallel requests
|
||||
* same file
|
||||
* different local files
|
||||
* different remote files
|
||||
* pre-generated thumbnails
|
||||
* non-pre-generated thumbnails
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
// 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"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/common/test"
|
||||
)
|
||||
|
||||
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)
|
||||
postgresContainerName = os.Getenv("POSTGRES_CONTAINER")
|
||||
)
|
||||
|
||||
var thumbnailPregenerationConfig = (`
|
||||
thumbnail_sizes:
|
||||
- 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"
|
||||
|
||||
var testDatabaseTemplate = "dbname=%s sslmode=disable binary_parameters=yes"
|
||||
|
||||
var timeout time.Duration
|
||||
|
||||
func startMediaAPI(suffix string, dynamicThumbnails bool) (*exec.Cmd, chan error, string) {
|
||||
dir, err := ioutil.TempDir("", serverType+"-server-test"+suffix)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
configFilename := serverType + "-server-test-config" + suffix + ".yaml"
|
||||
configFileContents := makeConfig(suffix, dir, dynamicThumbnails)
|
||||
|
||||
serverArgs := []string{
|
||||
"--config", configFilename,
|
||||
"--listen", "localhost:1777" + suffix,
|
||||
}
|
||||
|
||||
databases := []string{
|
||||
testDatabaseName + suffix,
|
||||
}
|
||||
|
||||
cmd, cmdChan := test.StartServer(
|
||||
serverType,
|
||||
serverArgs,
|
||||
suffix,
|
||||
configFilename,
|
||||
configFileContents,
|
||||
postgresDatabase,
|
||||
postgresContainerName,
|
||||
databases,
|
||||
)
|
||||
return cmd, cmdChan, dir
|
||||
}
|
||||
|
||||
func makeConfig(suffix, basePath string, dynamicThumbnails bool) string {
|
||||
return fmt.Sprintf(
|
||||
`
|
||||
server_name: "%s"
|
||||
base_path: %s
|
||||
max_file_size_bytes: %s
|
||||
database: "%s"
|
||||
dynamic_thumbnails: %s
|
||||
%s`,
|
||||
"localhost:1777"+suffix,
|
||||
basePath,
|
||||
"10485760",
|
||||
fmt.Sprintf(testDatabaseTemplate, testDatabaseName+suffix),
|
||||
strconv.FormatBool(dynamicThumbnails),
|
||||
thumbnailPregenerationConfig,
|
||||
)
|
||||
}
|
||||
|
||||
func cleanUpServer(cmd *exec.Cmd, dir string) {
|
||||
cmd.Process.Kill() // ensure server is dead, only cleaning up so don't care about errors this returns.
|
||||
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, server1Dir := startMediaAPI("1", false)
|
||||
defer cleanUpServer(server1Cmd, server1Dir)
|
||||
testDownload("1", "localhost:17771", "doesnotexist", "", 404, server1CmdChan)
|
||||
|
||||
// create server2 with dynamic thumbnail generation
|
||||
server2Cmd, server2CmdChan, server2Dir := startMediaAPI("2", true)
|
||||
defer cleanUpServer(server2Cmd, server2Dir)
|
||||
testDownload("2", "localhost:17772", "doesnotexist", "", 404, server2CmdChan)
|
||||
}
|
||||
|
||||
func getMediaURI(scheme, host, endpoint string, components []string) string {
|
||||
pathComponents := []string{
|
||||
host,
|
||||
"api",
|
||||
"_matrix",
|
||||
"media",
|
||||
"v1",
|
||||
endpoint,
|
||||
}
|
||||
pathComponents = append(pathComponents, components...)
|
||||
return scheme + path.Join(pathComponents...)
|
||||
}
|
||||
|
||||
func testDownload(suffix, origin, mediaID, wantedBody string, wantedStatusCode int, serverCmdChan chan error) {
|
||||
req, err := http.NewRequest(
|
||||
"GET",
|
||||
getMediaURI("http://", "localhost:1777"+suffix, "download", []string{
|
||||
origin,
|
||||
mediaID,
|
||||
}),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
testReq := &test.Request{
|
||||
Req: req,
|
||||
WantedStatusCode: wantedStatusCode,
|
||||
WantedBody: wantedBody,
|
||||
}
|
||||
testReq.Run("media-api", timeout, serverCmdChan)
|
||||
}
|
||||
Loading…
Reference in a new issue