From e87f775b1d96699da36817a8359551e6b338514c Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Fri, 11 Jun 2021 10:13:17 +0200 Subject: [PATCH 01/15] add tests for config --- go.mod | 3 +- go.sum | 2 + internal/api/application.go | 1 + internal/api/application_test.go | 105 ++++++++++ internal/configuration/configuration.go | 13 +- internal/configuration/configuration_test.go | 203 +++++++++++++++++++ tests/mockups/config.go | 43 ++++ tests/mockups/database.go | 13 ++ tests/mockups/dispatcher.go | 17 ++ tests/mockups/user.go | 21 ++ tests/request.go | 46 +++++ 11 files changed, 461 insertions(+), 6 deletions(-) create mode 100644 internal/api/application_test.go create mode 100644 internal/configuration/configuration_test.go create mode 100644 tests/mockups/config.go create mode 100644 tests/mockups/database.go create mode 100644 tests/mockups/dispatcher.go create mode 100644 tests/mockups/user.go create mode 100644 tests/request.go diff --git a/go.mod b/go.mod index e5c9e72..aaebf05 100644 --- a/go.mod +++ b/go.mod @@ -17,9 +17,10 @@ require ( github.com/mattn/go-sqlite3 v1.14.6 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/stretchr/testify v1.7.0 github.com/ugorji/go v1.2.4 // indirect golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/mysql v1.0.4 gorm.io/driver/sqlite v1.1.4 gorm.io/gorm v1.20.12 diff --git a/go.sum b/go.sum index c30c298..1f222e1 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.4 h1:cTciPbZ/VSOzCLKclmssnfQ/jyoVyOcJ3aoJyUV1Urc= diff --git a/internal/api/application.go b/internal/api/application.go index c598414..f90c9bd 100644 --- a/internal/api/application.go +++ b/internal/api/application.go @@ -114,6 +114,7 @@ func (h *ApplicationHandler) CreateApplication(ctx *gin.Context) { var createApplication model.CreateApplication if err := ctx.Bind(&createApplication); err != nil { + log.Println(err) return } diff --git a/internal/api/application_test.go b/internal/api/application_test.go new file mode 100644 index 0000000..f5efcb9 --- /dev/null +++ b/internal/api/application_test.go @@ -0,0 +1,105 @@ +package api + +import ( + "fmt" + "log" + "os" + "testing" + + "github.com/gin-gonic/gin" + "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/tests" + "github.com/pushbits/server/tests/mockups" + "github.com/stretchr/testify/assert" +) + +var TestApplicationHandler *ApplicationHandler +var TestConfig *configuration.Configuration + +func TestMain(m *testing.M) { + // Get main config and adapt + config, err := mockups.ReadConfig("../../config.yml", true) + if err != nil { + cleanUp() + log.Println("Can not read config: ", err) + os.Exit(1) + } + + config.Database.Connection = "pushbits-test.db" + config.Database.Dialect = "sqlite3" + TestConfig = config + + // Set up test environment + appHandler, err := getApplicationHandler(&TestConfig.Matrix) + if err != nil { + cleanUp() + log.Println("Can not set up application handler: ", err) + os.Exit(1) + } + + TestApplicationHandler = appHandler + + // Run + m.Run() + cleanUp() +} + +func TestApi_RegisterApplicationWithoutUser(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + reqWoUser := tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}} + _, c, err := reqWoUser.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + assert.Panicsf(func() { TestApplicationHandler.CreateApplication(c) }, "CreateApplication did not panic altough user is not in context") + +} + +func TestApi_RgisterApplication(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + testCases := make(map[int]tests.Request) + testCases[400] = tests.Request{Name: "Invalid Form Data", Method: "POST", Endpoint: "/application", Data: "k=1&v=abc"} + testCases[400] = tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}} + testCases[200] = tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}} + + user := mockups.GetAdminUser(TestConfig) + + for statusCode, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", user) + + TestApplicationHandler.CreateApplication(c) + + assert.Equalf(w.Code, statusCode, fmt.Sprintf("CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code)) + } +} + +// GetApplicationHandler creates and returns an application handler +func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) { + db, err := mockups.GetEmptyDatabase() + if err != nil { + return nil, err + } + + dispatcher, err := mockups.GetMatrixDispatcher(c.Homeserver, c.Username, c.Password) + if err != nil { + return nil, err + } + return &ApplicationHandler{ + DB: db, + DP: dispatcher, + }, nil +} + +func cleanUp() { + os.Remove("pushbits-test.db") +} diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go index dc3dc9e..3488b99 100644 --- a/internal/configuration/configuration.go +++ b/internal/configuration/configuration.go @@ -23,6 +23,13 @@ type Formatting struct { ColoredTitle bool `default:"false"` } +// Matrix holds credentials for a matrix account +type Matrix struct { + Homeserver string `default:"https://matrix.org"` + Username string `required:"true"` + Password string `required:"true"` +} + // Configuration holds values that can be configured by the user. type Configuration struct { Debug bool `default:"false"` @@ -39,11 +46,7 @@ type Configuration struct { Password string `default:"admin"` MatrixID string `required:"true"` } - Matrix struct { - Homeserver string `default:"https://matrix.org"` - Username string `required:"true"` - Password string `required:"true"` - } + Matrix Matrix Security struct { CheckHIBP bool `default:"false"` } diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go new file mode 100644 index 0000000..eebfc04 --- /dev/null +++ b/internal/configuration/configuration_test.go @@ -0,0 +1,203 @@ +package configuration + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + "testing" + + "github.com/jinzhu/configor" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +type Pair struct { + Is interface{} + Should interface{} +} + +func TestMain(m *testing.M) { + m.Run() + cleanUp() +} + +func TestConfiguration_GetMinimal(t *testing.T) { + err := writeMinimalConfig() + if err != nil { + fmt.Println("Could not write minimal config: ", err) + os.Exit(1) + } + + validateConfig(t) +} + +func TestConfiguration_GetValid(t *testing.T) { + assert := assert.New(t) + + err := writeValidConfig() + if err != nil { + fmt.Println("Could not write valid config: ", err) + os.Exit(1) + } + + validateConfig(t) + + config := Get() + + expectedValues := make(map[string]Pair) + expectedValues["config.Admin.MatrixID"] = Pair{config.Admin.MatrixID, "000000"} + expectedValues["config.Matrix.Username"] = Pair{config.Matrix.Username, "default-username"} + expectedValues["config.Matrix.Password"] = Pair{config.Matrix.Password, "default-password"} + + for name, pair := range expectedValues { + assert.Equalf(pair.Is, pair.Should, fmt.Sprintf("%s should be %v but is %v", name, pair.Should, pair.Is)) + } +} + +func TestConfiguration_GetEmpty(t *testing.T) { + err := writeEmptyConfig() + if err != nil { + fmt.Println("Could not write empty config: ", err) + os.Exit(1) + } + + assert.Panicsf(t, func() { Get() }, "Get() did not panic altough config is empty") +} + +func TestConfiguration_GetInvalid(t *testing.T) { + err := writeInvalidConfig() + if err != nil { + fmt.Println("Could not write empty config: ", err) + os.Exit(1) + } + + assert.Panicsf(t, func() { Get() }, "Get() did not panic altough config is empty") +} + +func TestConfiguaration_ConfigFiles(t *testing.T) { + files := configFiles() + + assert.Greater(t, len(files), 0) + for _, file := range files { + assert.Truef(t, strings.HasSuffix(file, ".yml"), "%s is no yaml file", file) + } +} + +// Checks if the values in the configuration are plausible +func validateConfig(t *testing.T) { + assert := assert.New(t) + assert.NotPanicsf(func() { Get() }, "Get configuration should not panic") + + config := Get() + asGreater := make(map[string]Pair) + asGreater["config.Crypto.Argon2.Memory"] = Pair{config.Crypto.Argon2.Memory, uint32(0)} + asGreater["config.Crypto.Argon2.Iterations"] = Pair{config.Crypto.Argon2.Iterations, uint32(0)} + asGreater["config.Crypto.Argon2.SaltLength"] = Pair{config.Crypto.Argon2.SaltLength, uint32(0)} + asGreater["config.Crypto.Argon2.KeyLength"] = Pair{config.Crypto.Argon2.KeyLength, uint32(0)} + asGreater["config.Crypto.Argon2.Parallelism"] = Pair{config.Crypto.Argon2.Parallelism, uint8(0)} + asGreater["config.HTTP.Port"] = Pair{config.HTTP.Port, 0} + for name, pair := range asGreater { + assert.Greaterf(pair.Is, pair.Should, fmt.Sprintf("%s should be > %v but is %v", name, pair.Should, pair.Is)) + } + + asFalse := make(map[string]bool) + asFalse["config.Formatting.ColoredTitle"] = config.Formatting.ColoredTitle + asFalse["config.Debug"] = config.Debug + asFalse["config.Security.CheckHIBP"] = config.Security.CheckHIBP + for name, value := range asFalse { + assert.Falsef(value, fmt.Sprintf("%s should be false but is %t", name, value)) + } +} + +type MinimalConfiguration struct { + Admin struct { + MatrixID string + } + Matrix struct { + Username string + Password string + } +} + +type InvalidConfiguration struct { + Debug int + HTTP struct { + ListenAddress bool + } + Admin struct { + Name int + } + Formatting string +} + +// Writes a minimal config to config.yml +func writeMinimalConfig() error { + cleanUp() + config := MinimalConfiguration{} + config.Admin.MatrixID = "000000" + config.Matrix.Username = "default-username" + config.Matrix.Password = "default-password" + + configString, err := yaml.Marshal(&config) + if err != nil { + return err + } + + return ioutil.WriteFile("config.yml", configString, 0644) +} + +// Writes a config with default values to config.yml +func writeValidConfig() error { + cleanUp() + + // Load minimal config to get default values + writeMinimalConfig() + config := &Configuration{} + err := configor.New(&configor.Config{ + Environment: "production", + ENVPrefix: "PUSHBITS", + ErrorOnUnmatchedKeys: true, + }).Load(config, "config.yml") + if err != nil { + return err + } + + config.Admin.MatrixID = "000000" + config.Matrix.Username = "default-username" + config.Matrix.Password = "default-password" + + configString, err := yaml.Marshal(&config) + if err != nil { + return err + } + + return ioutil.WriteFile("config.yml", configString, 0644) +} + +// Writes a config that is empty +func writeEmptyConfig() error { + cleanUp() + return ioutil.WriteFile("config.yml", []byte(""), 0644) +} + +// Writes a config with invalid entries +func writeInvalidConfig() error { + cleanUp() + config := InvalidConfiguration{} + config.Debug = 1337 + config.HTTP.ListenAddress = true + config.Admin.Name = 23 + config.Formatting = "Nice" + + configString, err := yaml.Marshal(&config) + if err != nil { + return err + } + + return ioutil.WriteFile("config.yml", configString, 0644) +} + +func cleanUp() error { + return os.Remove("config.yml") +} diff --git a/tests/mockups/config.go b/tests/mockups/config.go new file mode 100644 index 0000000..790d16e --- /dev/null +++ b/tests/mockups/config.go @@ -0,0 +1,43 @@ +package mockups + +import ( + "errors" + "io/ioutil" + "log" + "os" + + "github.com/pushbits/server/internal/configuration" +) + +// ReadConfig copies the given filename to the current folder and parses it as a config file. RemoveFile indicates whether to remove the copied file or not +func ReadConfig(filename string, removeFile bool) (config *configuration.Configuration, err error) { + defer func() { + if r := recover(); r != nil { + log.Println(r) + err = errors.New("Paniced while reading config") + } + }() + + if filename == "" { + return nil, errors.New("Empty filename") + } + + file, err := ioutil.ReadFile(filename) + + if err != nil { + return nil, err + } + + err = ioutil.WriteFile("config.yml", file, 0644) + if err != nil { + return nil, err + } + + config = configuration.Get() + + if removeFile { + os.Remove("config.yml") + } + + return config, nil +} diff --git a/tests/mockups/database.go b/tests/mockups/database.go new file mode 100644 index 0000000..f2b76fa --- /dev/null +++ b/tests/mockups/database.go @@ -0,0 +1,13 @@ +package mockups + +import ( + "github.com/pushbits/server/internal/authentication/credentials" + "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/internal/database" +) + +// GetEmptyDatabase returns an empty sqlite database object +func GetEmptyDatabase() (*database.Database, error) { + cm := credentials.CreateManager(false, configuration.CryptoConfig{}) + return database.Create(cm, "sqlite3", "pushbits-test.db") +} diff --git a/tests/mockups/dispatcher.go b/tests/mockups/dispatcher.go new file mode 100644 index 0000000..1b6a82a --- /dev/null +++ b/tests/mockups/dispatcher.go @@ -0,0 +1,17 @@ +package mockups + +import ( + "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/internal/dispatcher" +) + +// GetMatrixDispatcher creates and returns a matrix dispatcher +func GetMatrixDispatcher(homeserver, username, password string) (*dispatcher.Dispatcher, error) { + db, err := GetEmptyDatabase() + + if err != nil { + return nil, err + } + + return dispatcher.Create(db, homeserver, username, password, configuration.Formatting{}) +} diff --git a/tests/mockups/user.go b/tests/mockups/user.go new file mode 100644 index 0000000..a541cbd --- /dev/null +++ b/tests/mockups/user.go @@ -0,0 +1,21 @@ +package mockups + +import ( + "github.com/pushbits/server/internal/authentication/credentials" + "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/internal/model" +) + +// GetAdminUser returns an admin user +func GetAdminUser(c *configuration.Configuration) *model.User { + credentialsManager := credentials.CreateManager(false, c.Crypto) + hash, _ := credentialsManager.CreatePasswordHash(c.Admin.Password) + + return &model.User{ + ID: 1, + Name: c.Admin.Name, + PasswordHash: hash, + IsAdmin: true, + MatrixID: c.Admin.MatrixID, + } +} diff --git a/tests/request.go b/tests/request.go new file mode 100644 index 0000000..43a9651 --- /dev/null +++ b/tests/request.go @@ -0,0 +1,46 @@ +package tests + +import ( + "encoding/json" + "io" + "net/http/httptest" + "strings" + + "github.com/gin-gonic/gin" +) + +// Request holds information for a HTTP request +type Request struct { + Name string + Method string + Endpoint string + Data interface{} + Headers map[string]string +} + +// GetRequest returns a ResponseRecorder and gin context according to the data set in the Request. +// String data is passed as is, all other data types are marshaled before. +func (r *Request) GetRequest() (w *httptest.ResponseRecorder, c *gin.Context, err error) { + var body io.Reader + w = httptest.NewRecorder() + + switch r.Data.(type) { + case string: + body = strings.NewReader(r.Data.(string)) + default: + dataMarshaled, err := json.Marshal(r.Data) + if err != nil { + return nil, nil, err + } + body = strings.NewReader(string(dataMarshaled)) + } + + c, _ = gin.CreateTestContext(w) + c.Request = httptest.NewRequest(r.Method, r.Endpoint, body) + + for name, value := range r.Headers { + c.Request.Header.Set(name, value) + } + + return w, c, nil +} From ee212e11c36c0b1f195535da3e22a815e05b796e Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Fri, 11 Jun 2021 19:03:04 +0200 Subject: [PATCH 02/15] enhance application testing --- internal/api/application_test.go | 115 ++++++++++++++++++++++++++++--- tests/mockups/user.go | 22 ++++++ 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/internal/api/application_test.go b/internal/api/application_test.go index f5efcb9..2dcb368 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -1,20 +1,25 @@ package api import ( - "fmt" + "encoding/json" + "io/ioutil" "log" "os" "testing" "github.com/gin-gonic/gin" "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/internal/model" "github.com/pushbits/server/tests" "github.com/pushbits/server/tests/mockups" "github.com/stretchr/testify/assert" ) var TestApplicationHandler *ApplicationHandler -var TestConfig *configuration.Configuration +var TestUser *model.User + +// Collect all created applications to check & delete them later +var SuccessAplications []model.Application func TestMain(m *testing.M) { // Get main config and adapt @@ -27,10 +32,9 @@ func TestMain(m *testing.M) { config.Database.Connection = "pushbits-test.db" config.Database.Dialect = "sqlite3" - TestConfig = config // Set up test environment - appHandler, err := getApplicationHandler(&TestConfig.Matrix) + appHandler, err := getApplicationHandler(&config.Matrix) if err != nil { cleanUp() log.Println("Can not set up application handler: ", err) @@ -39,8 +43,12 @@ func TestMain(m *testing.M) { TestApplicationHandler = appHandler - // Run - m.Run() + // Run for each user + for _, user := range mockups.GetUsers(config) { + SuccessAplications = []model.Application{} + TestUser = user + m.Run() + } cleanUp() } @@ -67,7 +75,44 @@ func TestApi_RgisterApplication(t *testing.T) { testCases[400] = tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}} testCases[200] = tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}} - user := mockups.GetAdminUser(TestConfig) + for statusCode, req := range testCases { + var application model.Application + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", TestUser) + TestApplicationHandler.CreateApplication(c) + + // Parse body only for successful requests + if statusCode >= 200 && statusCode < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &application) + assert.NoErrorf(err, "Can not unmarshal request body") + if err != nil { + continue + } + + SuccessAplications = append(SuccessAplications, application) + } + + assert.Equalf(w.Code, statusCode, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code) + } +} + +func TestApi_GetApplications(t *testing.T) { + var applications []model.Application + + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + testCases := make(map[int]tests.Request) + testCases[200] = tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application"} for statusCode, req := range testCases { w, c, err := req.GetRequest() @@ -75,14 +120,45 @@ func TestApi_RgisterApplication(t *testing.T) { t.Fatalf(err.Error()) } - c.Set("user", user) + c.Set("user", TestUser) + TestApplicationHandler.GetApplications(c) - TestApplicationHandler.CreateApplication(c) + // Parse body only for successful requests + if statusCode >= 200 && statusCode < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &applications) + assert.NoErrorf(err, "Can not unmarshal request body") + if err != nil { + continue + } - assert.Equalf(w.Code, statusCode, fmt.Sprintf("CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code)) + assert.Truef(validateAllApplications(applications), "Did not find application created previously") + assert.Equalf(len(applications), len(SuccessAplications), "Created %d application(s) but got %d back", len(SuccessAplications), len(applications)) + } + + assert.Equalf(w.Code, statusCode, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code) } } +func TestApi_GetApplicationsWithoutUser(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + testCase := tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application"} + + _, c, err := testCase.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + assert.Panicsf(func() { TestApplicationHandler.GetApplications(c) }, "GetApplications did not panic altough user is not in context") + +} + // GetApplicationHandler creates and returns an application handler func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) { db, err := mockups.GetEmptyDatabase() @@ -100,6 +176,25 @@ func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) }, nil } +// True if all created applications are in list +func validateAllApplications(apps []model.Application) bool { + for _, successApp := range SuccessAplications { + foundApp := false + for _, app := range apps { + if app.ID == successApp.ID { + foundApp = true + break + } + } + + if !foundApp { + return false + } + } + + return true +} + func cleanUp() { os.Remove("pushbits-test.db") } diff --git a/tests/mockups/user.go b/tests/mockups/user.go index a541cbd..2e75639 100644 --- a/tests/mockups/user.go +++ b/tests/mockups/user.go @@ -19,3 +19,25 @@ func GetAdminUser(c *configuration.Configuration) *model.User { MatrixID: c.Admin.MatrixID, } } + +// GetUser returns an user +func GetUser(c *configuration.Configuration) *model.User { + credentialsManager := credentials.CreateManager(false, c.Crypto) + hash, _ := credentialsManager.CreatePasswordHash(c.Admin.Password) + + return &model.User{ + ID: 2, + Name: c.Admin.Name + "-normalo", + PasswordHash: hash, + IsAdmin: false, + MatrixID: c.Admin.MatrixID, + } +} + +// GetUsers returns a list of users +func GetUsers(c *configuration.Configuration) []*model.User { + var users []*model.User + users = append(users, GetAdminUser(c)) + users = append(users, GetUser(c)) + return users +} From 49ec908fce2791af31b97281e02f81ee2bc78351 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sat, 12 Jun 2021 17:57:55 +0200 Subject: [PATCH 03/15] add tests for deleting and updating applications --- internal/api/application_test.go | 156 ++++++++++++++++++++++++++++--- tests/request.go | 11 ++- 2 files changed, 149 insertions(+), 18 deletions(-) diff --git a/internal/api/application_test.go b/internal/api/application_test.go index 2dcb368..19d429d 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "fmt" "io/ioutil" "log" "os" @@ -70,12 +71,12 @@ func TestApi_RgisterApplication(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) - testCases := make(map[int]tests.Request) - testCases[400] = tests.Request{Name: "Invalid Form Data", Method: "POST", Endpoint: "/application", Data: "k=1&v=abc"} - testCases[400] = tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}} - testCases[200] = tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}} + testCases := make([]tests.Request, 0) + testCases = append(testCases, tests.Request{Name: "Invalid Form Data", Method: "POST", Endpoint: "/application", Data: "k=1&v=abc", ShouldStatus: 400}) + testCases = append(testCases, tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 400}) + testCases = append(testCases, tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 200}) - for statusCode, req := range testCases { + for _, req := range testCases { var application model.Application w, c, err := req.GetRequest() if err != nil { @@ -86,7 +87,7 @@ func TestApi_RgisterApplication(t *testing.T) { TestApplicationHandler.CreateApplication(c) // Parse body only for successful requests - if statusCode >= 200 && statusCode < 300 { + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { body, err := ioutil.ReadAll(w.Body) assert.NoErrorf(err, "Can not read request body") if err != nil { @@ -101,7 +102,7 @@ func TestApi_RgisterApplication(t *testing.T) { SuccessAplications = append(SuccessAplications, application) } - assert.Equalf(w.Code, statusCode, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code) + assert.Equalf(w.Code, req.ShouldStatus, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } } @@ -111,10 +112,10 @@ func TestApi_GetApplications(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) - testCases := make(map[int]tests.Request) - testCases[200] = tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application"} + testCases := make([]tests.Request, 0) + testCases = append(testCases, tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application", ShouldStatus: 200}) - for statusCode, req := range testCases { + for _, req := range testCases { w, c, err := req.GetRequest() if err != nil { t.Fatalf(err.Error()) @@ -124,7 +125,7 @@ func TestApi_GetApplications(t *testing.T) { TestApplicationHandler.GetApplications(c) // Parse body only for successful requests - if statusCode >= 200 && statusCode < 300 { + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { body, err := ioutil.ReadAll(w.Body) assert.NoErrorf(err, "Can not read request body") if err != nil { @@ -140,7 +141,7 @@ func TestApi_GetApplications(t *testing.T) { assert.Equalf(len(applications), len(SuccessAplications), "Created %d application(s) but got %d back", len(SuccessAplications), len(applications)) } - assert.Equalf(w.Code, statusCode, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, statusCode, w.Code) + assert.Equalf(w.Code, req.ShouldStatus, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } } @@ -159,6 +160,135 @@ func TestApi_GetApplicationsWithoutUser(t *testing.T) { } +func TestApi_GetApplicationErrors(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + // Arbitrary test cases + testCases := make(map[uint]tests.Request, 0) + testCases[0] = tests.Request{Name: "Requesting unknown application 0", Method: "GET", Endpoint: "/application/0", ShouldStatus: 404} + testCases[5555] = tests.Request{Name: "Requesting unknown application 5555", Method: "GET", Endpoint: "/application/5555", ShouldStatus: 404} + testCases[99999999999999999] = tests.Request{Name: "Requesting unknown application 99999999999999999", Method: "GET", Endpoint: "/application/99999999999999999", ShouldStatus: 404} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", TestUser) + c.Set("id", id) + TestApplicationHandler.GetApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } +} + +func TestApi_GetApplication(t *testing.T) { + var application model.Application + + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + // Previously generated applications + for _, app := range SuccessAplications { + req := tests.Request{Name: fmt.Sprintf("Requesting application %s (%d)", app.Name, app.ID), Method: "GET", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} + + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", TestUser) + c.Set("id", app.ID) + TestApplicationHandler.GetApplication(c) + + // Parse body only for successful requests + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &application) + assert.NoErrorf(err, "Can not unmarshal request body: %v", err) + if err != nil { + continue + } + + assert.Equalf(application.ID, app.ID, "Application ID should be %d but is %d", app.ID, application.ID) + assert.Equalf(application.Name, app.Name, "Application Name should be %s but is %s", app.Name, application.Name) + assert.Equalf(application.UserID, app.UserID, "Application user ID should be %d but is %d", app.UserID, application.UserID) + + } + + assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } +} + +func TestApi_UpdateApplication(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + testCases := make(map[uint]tests.Request) + // Previously generated applications + for _, app := range SuccessAplications { + newName := app.Name + "-new_name" + updateApp := model.UpdateApplication{ + Name: &newName, + } + updateAppBytes, err := json.Marshal(updateApp) + assert.NoErrorf(err, "Error on marshaling updateApplication struct") + + // Valid + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (valid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: string(updateAppBytes), Headers: map[string]string{"Content-Type": "application/json"}} + // Invalid + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (invalid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: "{}", Headers: map[string]string{"Content-Type": "application/json"}} + } + // Arbitrary test cases + testCases[5555] = tests.Request{Name: "Update application 5555", Method: "PUT", Endpoint: "/application/5555", ShouldStatus: 404, Data: "random data"} + testCases[5556] = tests.Request{Name: "Update application 5556", Method: "PUT", Endpoint: "/application/5556", ShouldStatus: 404, Data: `{"new_name": "new name"}`, Headers: map[string]string{"Content-Type": "application/json"}} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", TestUser) + c.Set("id", id) + TestApplicationHandler.UpdateApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "UpdateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } +} + +func TestApi_DeleteApplication(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + testCases := make(map[uint]tests.Request) + // Previously generated applications + for _, app := range SuccessAplications { + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Delete application %s (%d)", app.Name, app.ID), Method: "DELETE", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} + } + // Arbitrary test cases + testCases[5555] = tests.Request{Name: "Delete application 5555", Method: "DELETE", Endpoint: "/application/5555", ShouldStatus: 404} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", TestUser) + c.Set("id", id) + TestApplicationHandler.DeleteApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "DeleteApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } +} + // GetApplicationHandler creates and returns an application handler func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) { db, err := mockups.GetEmptyDatabase() @@ -196,5 +326,5 @@ func validateAllApplications(apps []model.Application) bool { } func cleanUp() { - os.Remove("pushbits-test.db") + //os.Remove("pushbits-test.db") } diff --git a/tests/request.go b/tests/request.go index 43a9651..bb786af 100644 --- a/tests/request.go +++ b/tests/request.go @@ -11,11 +11,12 @@ import ( // Request holds information for a HTTP request type Request struct { - Name string - Method string - Endpoint string - Data interface{} - Headers map[string]string + Name string + Method string + Endpoint string + Data interface{} + Headers map[string]string + ShouldStatus int } // GetRequest returns a ResponseRecorder and gin context according to the data set in the Request. From ef5409eb35bd82075c8a39df27b4a5aece9229b5 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 13 Jun 2021 18:09:57 +0200 Subject: [PATCH 04/15] add Tests for getID --- internal/api/application_test.go | 290 ++++++++++++++++--------------- internal/api/context_test.go | 39 +++++ 2 files changed, 193 insertions(+), 136 deletions(-) create mode 100644 internal/api/context_test.go diff --git a/internal/api/application_test.go b/internal/api/application_test.go index 19d429d..01f0d6a 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -17,10 +17,10 @@ import ( ) var TestApplicationHandler *ApplicationHandler -var TestUser *model.User +var TestUsers []*model.User // Collect all created applications to check & delete them later -var SuccessAplications []model.Application +var SuccessAplications map[uint][]model.Application func TestMain(m *testing.M) { // Get main config and adapt @@ -43,13 +43,10 @@ func TestMain(m *testing.M) { } TestApplicationHandler = appHandler + TestUsers = mockups.GetUsers(config) + SuccessAplications = make(map[uint][]model.Application) - // Run for each user - for _, user := range mockups.GetUsers(config) { - SuccessAplications = []model.Application{} - TestUser = user - m.Run() - } + m.Run() cleanUp() } @@ -67,7 +64,7 @@ func TestApi_RegisterApplicationWithoutUser(t *testing.T) { } -func TestApi_RgisterApplication(t *testing.T) { +func TestApi_RegisterApplication(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) @@ -76,33 +73,36 @@ func TestApi_RgisterApplication(t *testing.T) { testCases = append(testCases, tests.Request{Name: "Invalid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test1", "strict_compatibility": "oh yes"}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 400}) testCases = append(testCases, tests.Request{Name: "Valid JSON Data", Method: "POST", Endpoint: "/application", Data: `{"name": "test2", "strict_compatibility": true}`, Headers: map[string]string{"Content-Type": "application/json"}, ShouldStatus: 200}) - for _, req := range testCases { - var application model.Application - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) - } - - c.Set("user", TestUser) - TestApplicationHandler.CreateApplication(c) - - // Parse body only for successful requests - if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { - body, err := ioutil.ReadAll(w.Body) - assert.NoErrorf(err, "Can not read request body") + for _, user := range TestUsers { + SuccessAplications[user.ID] = make([]model.Application, 0) + for _, req := range testCases { + var application model.Application + w, c, err := req.GetRequest() if err != nil { - continue - } - err = json.Unmarshal(body, &application) - assert.NoErrorf(err, "Can not unmarshal request body") - if err != nil { - continue + t.Fatalf(err.Error()) } - SuccessAplications = append(SuccessAplications, application) - } + c.Set("user", user) + TestApplicationHandler.CreateApplication(c) - assert.Equalf(w.Code, req.ShouldStatus, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + // Parse body only for successful requests + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &application) + assert.NoErrorf(err, "Can not unmarshal request body") + if err != nil { + continue + } + + SuccessAplications[user.ID] = append(SuccessAplications[user.ID], application) + } + + assert.Equalf(w.Code, req.ShouldStatus, "CreateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } } } @@ -115,33 +115,35 @@ func TestApi_GetApplications(t *testing.T) { testCases := make([]tests.Request, 0) testCases = append(testCases, tests.Request{Name: "Valid Request", Method: "GET", Endpoint: "/application", ShouldStatus: 200}) - for _, req := range testCases { - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) - } - - c.Set("user", TestUser) - TestApplicationHandler.GetApplications(c) - - // Parse body only for successful requests - if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { - body, err := ioutil.ReadAll(w.Body) - assert.NoErrorf(err, "Can not read request body") + for _, user := range TestUsers { + for _, req := range testCases { + w, c, err := req.GetRequest() if err != nil { - continue - } - err = json.Unmarshal(body, &applications) - assert.NoErrorf(err, "Can not unmarshal request body") - if err != nil { - continue + t.Fatalf(err.Error()) } - assert.Truef(validateAllApplications(applications), "Did not find application created previously") - assert.Equalf(len(applications), len(SuccessAplications), "Created %d application(s) but got %d back", len(SuccessAplications), len(applications)) - } + c.Set("user", user) + TestApplicationHandler.GetApplications(c) - assert.Equalf(w.Code, req.ShouldStatus, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + // Parse body only for successful requests + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &applications) + assert.NoErrorf(err, "Can not unmarshal request body") + if err != nil { + continue + } + + assert.Truef(validateAllApplications(user, applications), "Did not find application created previously") + assert.Equalf(len(applications), len(SuccessAplications[user.ID]), "Created %d application(s) but got %d back", len(SuccessAplications[user.ID]), len(applications)) + } + + assert.Equalf(w.Code, req.ShouldStatus, "GetApplications (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } } } @@ -170,17 +172,19 @@ func TestApi_GetApplicationErrors(t *testing.T) { testCases[5555] = tests.Request{Name: "Requesting unknown application 5555", Method: "GET", Endpoint: "/application/5555", ShouldStatus: 404} testCases[99999999999999999] = tests.Request{Name: "Requesting unknown application 99999999999999999", Method: "GET", Endpoint: "/application/99999999999999999", ShouldStatus: 404} - for id, req := range testCases { - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) + for _, user := range TestUsers { + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("user", user) + c.Set("id", id) + TestApplicationHandler.GetApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } - - c.Set("user", TestUser) - c.Set("id", id) - TestApplicationHandler.GetApplication(c) - - assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } } @@ -191,38 +195,40 @@ func TestApi_GetApplication(t *testing.T) { gin.SetMode(gin.TestMode) // Previously generated applications - for _, app := range SuccessAplications { - req := tests.Request{Name: fmt.Sprintf("Requesting application %s (%d)", app.Name, app.ID), Method: "GET", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} + for _, user := range TestUsers { + for _, app := range SuccessAplications[user.ID] { + req := tests.Request{Name: fmt.Sprintf("Requesting application %s (%d)", app.Name, app.ID), Method: "GET", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) - } - - c.Set("user", TestUser) - c.Set("id", app.ID) - TestApplicationHandler.GetApplication(c) - - // Parse body only for successful requests - if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { - body, err := ioutil.ReadAll(w.Body) - assert.NoErrorf(err, "Can not read request body") + w, c, err := req.GetRequest() if err != nil { - continue - } - err = json.Unmarshal(body, &application) - assert.NoErrorf(err, "Can not unmarshal request body: %v", err) - if err != nil { - continue + t.Fatalf(err.Error()) } - assert.Equalf(application.ID, app.ID, "Application ID should be %d but is %d", app.ID, application.ID) - assert.Equalf(application.Name, app.Name, "Application Name should be %s but is %s", app.Name, application.Name) - assert.Equalf(application.UserID, app.UserID, "Application user ID should be %d but is %d", app.UserID, application.UserID) + c.Set("user", user) + c.Set("id", app.ID) + TestApplicationHandler.GetApplication(c) + // Parse body only for successful requests + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + body, err := ioutil.ReadAll(w.Body) + assert.NoErrorf(err, "Can not read request body") + if err != nil { + continue + } + err = json.Unmarshal(body, &application) + assert.NoErrorf(err, "Can not unmarshal request body: %v", err) + if err != nil { + continue + } + + assert.Equalf(application.ID, app.ID, "Application ID should be %d but is %d", app.ID, application.ID) + assert.Equalf(application.Name, app.Name, "Application Name should be %s but is %s", app.Name, application.Name) + assert.Equalf(application.UserID, app.UserID, "Application user ID should be %d but is %d", app.UserID, application.UserID) + + } + + assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } - - assert.Equalf(w.Code, req.ShouldStatus, "GetApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } } @@ -230,36 +236,38 @@ func TestApi_UpdateApplication(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) - testCases := make(map[uint]tests.Request) - // Previously generated applications - for _, app := range SuccessAplications { - newName := app.Name + "-new_name" - updateApp := model.UpdateApplication{ - Name: &newName, + for _, user := range TestUsers { + testCases := make(map[uint]tests.Request) + // Previously generated applications + for _, app := range SuccessAplications[user.ID] { + newName := app.Name + "-new_name" + updateApp := model.UpdateApplication{ + Name: &newName, + } + updateAppBytes, err := json.Marshal(updateApp) + assert.NoErrorf(err, "Error on marshaling updateApplication struct") + + // Valid + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (valid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: string(updateAppBytes), Headers: map[string]string{"Content-Type": "application/json"}} + // Invalid + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (invalid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: "{}", Headers: map[string]string{"Content-Type": "application/json"}} } - updateAppBytes, err := json.Marshal(updateApp) - assert.NoErrorf(err, "Error on marshaling updateApplication struct") + // Arbitrary test cases + testCases[5555] = tests.Request{Name: "Update application 5555", Method: "PUT", Endpoint: "/application/5555", ShouldStatus: 404, Data: "random data"} + testCases[5556] = tests.Request{Name: "Update application 5556", Method: "PUT", Endpoint: "/application/5556", ShouldStatus: 404, Data: `{"new_name": "new name"}`, Headers: map[string]string{"Content-Type": "application/json"}} - // Valid - testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (valid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: string(updateAppBytes), Headers: map[string]string{"Content-Type": "application/json"}} - // Invalid - testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Update application (invalid) %s (%d)", app.Name, app.ID), Method: "PUT", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200, Data: "{}", Headers: map[string]string{"Content-Type": "application/json"}} - } - // Arbitrary test cases - testCases[5555] = tests.Request{Name: "Update application 5555", Method: "PUT", Endpoint: "/application/5555", ShouldStatus: 404, Data: "random data"} - testCases[5556] = tests.Request{Name: "Update application 5556", Method: "PUT", Endpoint: "/application/5556", ShouldStatus: 404, Data: `{"new_name": "new name"}`, Headers: map[string]string{"Content-Type": "application/json"}} + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } - for id, req := range testCases { - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) + c.Set("user", user) + c.Set("id", id) + TestApplicationHandler.UpdateApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "UpdateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } - - c.Set("user", TestUser) - c.Set("id", id) - TestApplicationHandler.UpdateApplication(c) - - assert.Equalf(w.Code, req.ShouldStatus, "UpdateApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) } } @@ -267,25 +275,27 @@ func TestApi_DeleteApplication(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) - testCases := make(map[uint]tests.Request) - // Previously generated applications - for _, app := range SuccessAplications { - testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Delete application %s (%d)", app.Name, app.ID), Method: "DELETE", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} - } - // Arbitrary test cases - testCases[5555] = tests.Request{Name: "Delete application 5555", Method: "DELETE", Endpoint: "/application/5555", ShouldStatus: 404} - - for id, req := range testCases { - w, c, err := req.GetRequest() - if err != nil { - t.Fatalf(err.Error()) + for _, user := range TestUsers { + testCases := make(map[uint]tests.Request) + // Previously generated applications + for _, app := range SuccessAplications[user.ID] { + testCases[app.ID] = tests.Request{Name: fmt.Sprintf("Delete application %s (%d)", app.Name, app.ID), Method: "DELETE", Endpoint: fmt.Sprintf("/application/%d", app.ID), ShouldStatus: 200} } + // Arbitrary test cases + testCases[5555] = tests.Request{Name: "Delete application 5555", Method: "DELETE", Endpoint: "/application/5555", ShouldStatus: 404} - c.Set("user", TestUser) - c.Set("id", id) - TestApplicationHandler.DeleteApplication(c) + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } - assert.Equalf(w.Code, req.ShouldStatus, "DeleteApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + c.Set("user", user) + c.Set("id", id) + TestApplicationHandler.DeleteApplication(c) + + assert.Equalf(w.Code, req.ShouldStatus, "DeleteApplication (Test case: \"%s\") should return status code %v but is %v.", req.Name, req.ShouldStatus, w.Code) + } } } @@ -307,8 +317,16 @@ func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) } // True if all created applications are in list -func validateAllApplications(apps []model.Application) bool { - for _, successApp := range SuccessAplications { +func validateAllApplications(user *model.User, apps []model.Application) bool { + if _, ok := SuccessAplications[user.ID]; !ok { + if len(apps) == 0 { + return true + } else { + return false + } + } + + for _, successApp := range SuccessAplications[user.ID] { foundApp := false for _, app := range apps { if app.ID == successApp.ID { @@ -326,5 +344,5 @@ func validateAllApplications(apps []model.Application) bool { } func cleanUp() { - //os.Remove("pushbits-test.db") + os.Remove("pushbits-test.db") } diff --git a/internal/api/context_test.go b/internal/api/context_test.go new file mode 100644 index 0000000..4432c9d --- /dev/null +++ b/internal/api/context_test.go @@ -0,0 +1,39 @@ +package api + +import ( + "testing" + + "github.com/gin-gonic/gin" + "github.com/pushbits/server/internal/model" + "github.com/pushbits/server/tests" + "github.com/stretchr/testify/assert" +) + +func TestApi_getID(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + testValue := uint(1337) + + testCases := make(map[interface{}]tests.Request) + testCases[-1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + testCases[uint(1)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + testCases[uint(0)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + testCases[uint(500)] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + testCases["test"] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + testCases[model.Application{}] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + testCases[&model.Application{}] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + testCases[&testValue] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 500} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("id", id) + getID(c) + + assert.Equalf(w.Code, req.ShouldStatus, "getApi id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code) + } +} From 46dd19b07d5bad316fdf5971a935a4118a8fc08e Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Thu, 17 Jun 2021 17:33:07 +0200 Subject: [PATCH 05/15] getApplication testing --- internal/api/context_test.go | 50 +++++++++++++++++++++++++++++++++++- tests/mockups/application.go | 32 +++++++++++++++++++++++ tests/mockups/database.go | 13 ++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/mockups/application.go diff --git a/internal/api/context_test.go b/internal/api/context_test.go index 4432c9d..7f9975f 100644 --- a/internal/api/context_test.go +++ b/internal/api/context_test.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pushbits/server/internal/model" "github.com/pushbits/server/tests" + "github.com/pushbits/server/tests/mockups" "github.com/stretchr/testify/assert" ) @@ -32,8 +33,55 @@ func TestApi_getID(t *testing.T) { } c.Set("id", id) - getID(c) + idReturned, err := getID(c) + + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + idUint, ok := id.(uint) + if ok { + assert.Equalf(idReturned, idUint, "getApi id was set to %d but result is %d", idUint, idReturned) + } + assert.NoErrorf(err, "getId with id %v (%t) returned an error altough it should not: %v", id, id, err) + } else { + assert.Errorf(err, "getId with id %v (%t) returned no error altough it should", id, id) + } assert.Equalf(w.Code, req.ShouldStatus, "getApi id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code) } } + +func TestApi_getApplication(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + // Generate a mock database + db, err := mockups.GetEmptyDatabase() + assert.NoErrorf(err, "Could not get database: ", err) + + applications := mockups.GetAllApplications() + mockups.AddApplicationsToDb(db, applications) + + testCases := make(map[uint]tests.Request) + testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 404} + testCases[1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + testCases[2] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("id", id) + app, err := getApplication(c, db) + + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + assert.Equalf(app.ID, id, "getApplication id was set to %d but resulting app id is %d", id, app.ID) + assert.NoErrorf(err, "getApplication with id %v (%t) returned an error altough it should not: %v", id, id, err) + } else { + assert.Errorf(err, "getApplication with id %v (%t) returned no error altough it should", id, id) + } + + assert.Equalf(w.Code, req.ShouldStatus, "getApplication id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code) + + } +} diff --git a/tests/mockups/application.go b/tests/mockups/application.go new file mode 100644 index 0000000..754b37e --- /dev/null +++ b/tests/mockups/application.go @@ -0,0 +1,32 @@ +package mockups + +import "github.com/pushbits/server/internal/model" + +// GetApplication1 returns an application with id 1 +func GetApplication1() *model.Application { + return &model.Application{ + ID: 1, + Token: "1234567890abcdefghijklmn", + UserID: 1, + Name: "App1", + } +} + +// GetApplication2 returns an application with id 2 +func GetApplication2() *model.Application { + return &model.Application{ + ID: 2, + Token: "0987654321xyzabcdefghij", + UserID: 1, + Name: "App2", + } +} + +// GetAllApplications returns all mock-applications as a list +func GetAllApplications() []*model.Application { + applications := make([]*model.Application, 0) + applications = append(applications, GetApplication1()) + applications = append(applications, GetApplication2()) + + return applications +} diff --git a/tests/mockups/database.go b/tests/mockups/database.go index f2b76fa..6914d3c 100644 --- a/tests/mockups/database.go +++ b/tests/mockups/database.go @@ -4,6 +4,7 @@ import ( "github.com/pushbits/server/internal/authentication/credentials" "github.com/pushbits/server/internal/configuration" "github.com/pushbits/server/internal/database" + "github.com/pushbits/server/internal/model" ) // GetEmptyDatabase returns an empty sqlite database object @@ -11,3 +12,15 @@ func GetEmptyDatabase() (*database.Database, error) { cm := credentials.CreateManager(false, configuration.CryptoConfig{}) return database.Create(cm, "sqlite3", "pushbits-test.db") } + +// AddApplicationsToDb inserts the applications apps into the database db +func AddApplicationsToDb(db *database.Database, apps []*model.Application) error { + for _, app := range apps { + err := db.CreateApplication(app) + if err != nil { + return err + } + } + + return nil +} From e6f24c4458b8482b902d4f8535bea8be45d7c8b0 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sat, 19 Jun 2021 16:59:30 +0200 Subject: [PATCH 06/15] add test for getUser & add readme --- README.md | 30 +++++++++++++++++++++++ execute_tests.sh | 1 + internal/api/application_test.go | 28 ++++++++++++--------- internal/api/context_test.go | 42 +++++++++++++++++++++++++++----- tests/mockups/database.go | 30 +++++++++++++++++++++-- tests/mockups/dispatcher.go | 4 +-- 6 files changed, 114 insertions(+), 21 deletions(-) create mode 100644 execute_tests.sh diff --git a/README.md b/README.md index 8bb3256..9eff325 100644 --- a/README.md +++ b/README.md @@ -157,3 +157,33 @@ git clone https://github.com/pushbits/server.git ``` [![Stargazers over time](https://starchart.cc/pushbits/server.svg)](https://starchart.cc/pushbits/server) + +### Testing + +Testing is essential for deliviering a good and reliable software. PushBits uses golangs integrated test features. Unfortunately writing tests is quite time consuming and therefore not every feature and every line of code is automatically tested. Feel free to help us improve our tests. + +Some tests depend on confidential configuration data. Therefore provide a `config.yml` in PushBits main folder. + +To run tests for a single (sub)module you can simply execute the following command in the modules folder. + +```bash +go test +``` + +To get the testing coverage for a module use the `-cover` flag. + +```bash +go test -cover +``` + +To execute a single test use the `-run` flag. + +```bash +go test -run "TestApi_getUser" +``` + +Running tests for all PushBits module is done by the `execute_tests.sh` script provided. + +```bash +bash execute_tests.sh +``` \ No newline at end of file diff --git a/execute_tests.sh b/execute_tests.sh new file mode 100644 index 0000000..50c5ff4 --- /dev/null +++ b/execute_tests.sh @@ -0,0 +1 @@ +find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test -cover \ No newline at end of file diff --git a/internal/api/application_test.go b/internal/api/application_test.go index 01f0d6a..a09fd75 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -10,6 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pushbits/server/internal/configuration" + "github.com/pushbits/server/internal/database" "github.com/pushbits/server/internal/model" "github.com/pushbits/server/tests" "github.com/pushbits/server/tests/mockups" @@ -18,6 +19,7 @@ import ( var TestApplicationHandler *ApplicationHandler var TestUsers []*model.User +var TestDatabase *database.Database // Collect all created applications to check & delete them later var SuccessAplications map[uint][]model.Application @@ -35,7 +37,15 @@ func TestMain(m *testing.M) { config.Database.Dialect = "sqlite3" // Set up test environment - appHandler, err := getApplicationHandler(&config.Matrix) + db, err := mockups.GetEmptyDatabase(config.Crypto) + if err != nil { + cleanUp() + log.Println("Can not set up database: ", err) + os.Exit(1) + } + TestDatabase = db + + appHandler, err := getApplicationHandler(config) if err != nil { cleanUp() log.Println("Can not set up application handler: ", err) @@ -46,6 +56,7 @@ func TestMain(m *testing.M) { TestUsers = mockups.GetUsers(config) SuccessAplications = make(map[uint][]model.Application) + // Run m.Run() cleanUp() } @@ -300,18 +311,13 @@ func TestApi_DeleteApplication(t *testing.T) { } // GetApplicationHandler creates and returns an application handler -func getApplicationHandler(c *configuration.Matrix) (*ApplicationHandler, error) { - db, err := mockups.GetEmptyDatabase() - if err != nil { - return nil, err - } - - dispatcher, err := mockups.GetMatrixDispatcher(c.Homeserver, c.Username, c.Password) +func getApplicationHandler(c *configuration.Configuration) (*ApplicationHandler, error) { + dispatcher, err := mockups.GetMatrixDispatcher(c.Matrix.Homeserver, c.Matrix.Username, c.Matrix.Password, c.Crypto) if err != nil { return nil, err } return &ApplicationHandler{ - DB: db, + DB: TestDatabase, DP: dispatcher, }, nil } @@ -321,9 +327,9 @@ func validateAllApplications(user *model.User, apps []model.Application) bool { if _, ok := SuccessAplications[user.ID]; !ok { if len(apps) == 0 { return true - } else { - return false } + + return false } for _, successApp := range SuccessAplications[user.ID] { diff --git a/internal/api/context_test.go b/internal/api/context_test.go index 7f9975f..f3bcdf8 100644 --- a/internal/api/context_test.go +++ b/internal/api/context_test.go @@ -53,13 +53,10 @@ func TestApi_getApplication(t *testing.T) { assert := assert.New(t) gin.SetMode(gin.TestMode) - // Generate a mock database - db, err := mockups.GetEmptyDatabase() - assert.NoErrorf(err, "Could not get database: ", err) - applications := mockups.GetAllApplications() - mockups.AddApplicationsToDb(db, applications) + mockups.AddApplicationsToDb(TestDatabase, applications) + // No testing of invalid ids as that is tested in TestApi_getID already testCases := make(map[uint]tests.Request) testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 404} testCases[1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} @@ -72,7 +69,7 @@ func TestApi_getApplication(t *testing.T) { } c.Set("id", id) - app, err := getApplication(c, db) + app, err := getApplication(c, TestDatabase) if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { assert.Equalf(app.ID, id, "getApplication id was set to %d but resulting app id is %d", id, app.ID) @@ -85,3 +82,36 @@ func TestApi_getApplication(t *testing.T) { } } + +func TestApi_getUser(t *testing.T) { + assert := assert.New(t) + gin.SetMode(gin.TestMode) + + _, err := mockups.AddUsersToDb(TestDatabase, TestUsers) + assert.NoErrorf(err, "Adding users to database failed: %v", err) + + // No testing of invalid ids as that is tested in TestApi_getID already + testCases := make(map[uint]tests.Request) + testCases[500] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 404} + testCases[1] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + testCases[2] = tests.Request{Name: "-", Method: "GET", Endpoint: "/", Data: "", ShouldStatus: 200} + + for id, req := range testCases { + w, c, err := req.GetRequest() + if err != nil { + t.Fatalf(err.Error()) + } + + c.Set("id", id) + user, err := getUser(c, TestDatabase) + + if req.ShouldStatus >= 200 && req.ShouldStatus < 300 { + assert.Equalf(user.ID, id, "getUser id was set to %d but resulting app id is %d", id, user.ID) + assert.NoErrorf(err, "getUser with id %v (%t) returned an error altough it should not: %v", id, id, err) + } else { + assert.Errorf(err, "getUser with id %v (%t) returned no error altough it should", id, id) + } + + assert.Equalf(w.Code, req.ShouldStatus, "getUser id was set to %v (%T) and should result in status code %d but code is %d", id, id, req.ShouldStatus, w.Code) + } +} diff --git a/tests/mockups/database.go b/tests/mockups/database.go index 6914d3c..40348d5 100644 --- a/tests/mockups/database.go +++ b/tests/mockups/database.go @@ -8,8 +8,8 @@ import ( ) // GetEmptyDatabase returns an empty sqlite database object -func GetEmptyDatabase() (*database.Database, error) { - cm := credentials.CreateManager(false, configuration.CryptoConfig{}) +func GetEmptyDatabase(confCrypto configuration.CryptoConfig) (*database.Database, error) { + cm := credentials.CreateManager(false, confCrypto) return database.Create(cm, "sqlite3", "pushbits-test.db") } @@ -24,3 +24,29 @@ func AddApplicationsToDb(db *database.Database, apps []*model.Application) error return nil } + +// AddUsersToDb adds the users to the database and sets their username as a password, returns list of added users +func AddUsersToDb(db *database.Database, users []*model.User) ([]*model.User, error) { + addedUsers := make([]*model.User, 0) + + for _, user := range users { + extUser := model.ExternalUser{ + ID: user.ID, + Name: user.Name, + IsAdmin: user.IsAdmin, + MatrixID: user.MatrixID, + } + credentials := model.UserCredentials{ + Password: user.Name, + } + createUser := model.CreateUser{ExternalUser: extUser, UserCredentials: credentials} + + newUser, err := db.CreateUser(createUser) + addedUsers = append(addedUsers, newUser) + if err != nil { + return nil, err + } + } + + return addedUsers, nil +} diff --git a/tests/mockups/dispatcher.go b/tests/mockups/dispatcher.go index 1b6a82a..6a5b314 100644 --- a/tests/mockups/dispatcher.go +++ b/tests/mockups/dispatcher.go @@ -6,8 +6,8 @@ import ( ) // GetMatrixDispatcher creates and returns a matrix dispatcher -func GetMatrixDispatcher(homeserver, username, password string) (*dispatcher.Dispatcher, error) { - db, err := GetEmptyDatabase() +func GetMatrixDispatcher(homeserver, username, password string, confCrypto configuration.CryptoConfig) (*dispatcher.Dispatcher, error) { + db, err := GetEmptyDatabase(confCrypto) if err != nil { return nil, err From 36b6248a254b8938f59a9406b7aa7803fcfa9e68 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:03:07 +0200 Subject: [PATCH 07/15] resolve conflicts --- go.mod | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index aaebf05..acd5922 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,8 @@ require ( github.com/modern-go/reflect2 v1.0.1 // indirect github.com/stretchr/testify v1.7.0 github.com/ugorji/go v1.2.4 // indirect - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect + golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect + golang.org/x/tools v0.1.3 // indirect gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/mysql v1.0.4 gorm.io/driver/sqlite v1.1.4 From ea8a664eea16fbff1270e05ffd8fed4eaa98b50e Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:11:06 +0200 Subject: [PATCH 08/15] Update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index acd5922..3c4df8e 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/ugorji/go v1.2.4 // indirect golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect golang.org/x/tools v0.1.3 // indirect - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/mysql v1.0.4 gorm.io/driver/sqlite v1.1.4 gorm.io/gorm v1.20.12 From 77f0990d46eee9763bfc77cd5b01cef9119b22cb Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:18:11 +0200 Subject: [PATCH 09/15] update gomod & gosum --- go.mod | 4 ++-- go.sum | 18 ++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 3c4df8e..8de48c8 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,8 @@ require ( github.com/stretchr/testify v1.7.0 github.com/ugorji/go v1.2.4 // indirect golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect - golang.org/x/tools v0.1.3 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/yaml.v2 v2.4.0 gorm.io/driver/mysql v1.0.4 gorm.io/driver/sqlite v1.1.4 gorm.io/gorm v1.20.12 diff --git a/go.sum b/go.sum index 1f222e1..3a1ffae 100644 --- a/go.sum +++ b/go.sum @@ -17,13 +17,11 @@ github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8c github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.3.0 h1:nZU+7q+yJoFmwvNgv/LnPUkwPal62+b2xXj0AU1Es7o= github.com/go-playground/validator/v10 v10.3.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -46,11 +44,9 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -61,11 +57,9 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -73,17 +67,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.4 h1:cTciPbZ/VSOzCLKclmssnfQ/jyoVyOcJ3aoJyUV1Urc= github.com/ugorji/go v1.2.4/go.mod h1:EuaSCk8iZMdIspsu6HXH7X2UGKw1ezO4wCfGszGmmo4= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.4 h1:C5VurWRRCKjuENsbM6GYVw8W++WVW9rSxoACKIvxzz8= github.com/ugorji/go/codec v1.2.4/go.mod h1:bWBu1+kIRWcF8uMklKaJrR6fTWQOwAlrIzX22pHwryA= @@ -95,14 +85,15 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -113,7 +104,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= From dafc815be5ff58962f310f0b37633ce2762cfd59 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:39:10 +0200 Subject: [PATCH 10/15] move errors to new package to break import cycle --- app/test_notifications.py | 168 ++++++++++++++++++++++++++++ execute_tests.sh | 2 +- go.sum | 11 ++ internal/api/errors.go | 5 - internal/api/util.go | 3 +- internal/dispatcher/notification.go | 12 +- internal/pberrors/errors.go | 6 + tests/mockups/dispatcher.go | 8 +- 8 files changed, 195 insertions(+), 20 deletions(-) create mode 100644 app/test_notifications.py delete mode 100644 internal/api/errors.go create mode 100644 internal/pberrors/errors.go diff --git a/app/test_notifications.py b/app/test_notifications.py new file mode 100644 index 0000000..c12d5e4 --- /dev/null +++ b/app/test_notifications.py @@ -0,0 +1,168 @@ +import requests, json + +token = 'AxZTwBZXs2YK1J5IZa0fyCcfHz9cYM9VjaO627eMSbAXAMdwFluGZSOTB4Vk3RHY' + +url = 'https://push.remote.alexanderebhart.de/message?token=' + token +headers = {'content-type': 'application/json'} + +messages = [ + { + "message": "
", + "title": "NEW TEST", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + } + }, + { + "message": "line
break", + "title": "Linebreak single br", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + } + }, + { + "message": "line \n break", + "title": "Linebreak single n", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + } + }, + { + "message": """line + break""", + "title": "Linebreak native", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + } + }, + { + "message": "# Heading 1\n\n###### Heading 6\n\nAlt-H1\n=====\n\n**bold**\n\n_curly_\n\n~~Strike through~~\n\n[Link](google.com)\n\n* list1 \n* list2\n\n1. another list\n2. numerated\n\n![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png)\n\n`some inline code`\n\n```\nA code block\n```\n\n> Blockquote", + "title": "Markdown styling", + "extras": + { + "client::display": + { + "contentType": "text/markdown" + } + } + }, + { + "message": "Red", + "title": "HTML", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + } + }, +] + +priorities = [ + { + "message": "Some text", + "title": "Prio 0", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": 0 + }, + { + "message": "Some text", + "title": "Prio 3", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": 3 + }, + { + "message": "Some text", + "title": "Prio 4", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": 4 + }, + { + "message": "Some text", + "title": "Prio 15", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": 15 + }, + { + "message": "Some text", + "title": "Prio 21", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": 21 + }, + { + "message": "Some text", + "title": "Prio -5", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + "priority": -5 + }, + { + "message": "Some text", + "title": "No Prio", + "extras": + { + "client::display": + { + "contentType": "text/html" + } + }, + + }, +] + + +for data in priorities: + x = requests.post(url, data = json.dumps(data), headers=headers) + print(x.text) \ No newline at end of file diff --git a/execute_tests.sh b/execute_tests.sh index 50c5ff4..863ee90 100644 --- a/execute_tests.sh +++ b/execute_tests.sh @@ -1 +1 @@ -find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test -cover \ No newline at end of file +find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test -cover diff --git a/go.sum b/go.sum index b2e92a5..f61cc1d 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,17 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbq golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/api/errors.go b/internal/api/errors.go deleted file mode 100644 index 64c744a..0000000 --- a/internal/api/errors.go +++ /dev/null @@ -1,5 +0,0 @@ -package api - -import "errors" - -var ErrorMessageNotFound = errors.New("message not found") diff --git a/internal/api/util.go b/internal/api/util.go index d045139..ff9e481 100644 --- a/internal/api/util.go +++ b/internal/api/util.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/pushbits/server/internal/authentication" + "github.com/pushbits/server/internal/pberrors" "github.com/gin-gonic/gin" ) @@ -13,7 +14,7 @@ func successOrAbort(ctx *gin.Context, code int, err error) bool { if err != nil { // If we know the error force error code switch err { - case ErrorMessageNotFound: + case pberrors.ErrorMessageNotFound: ctx.AbortWithError(http.StatusNotFound, err) default: ctx.AbortWithError(code, err) diff --git a/internal/dispatcher/notification.go b/internal/dispatcher/notification.go index 9fce7a0..67dcad9 100644 --- a/internal/dispatcher/notification.go +++ b/internal/dispatcher/notification.go @@ -8,8 +8,8 @@ import ( "github.com/gomarkdown/markdown" "github.com/matrix-org/gomatrix" - "github.com/pushbits/server/internal/api" "github.com/pushbits/server/internal/model" + "github.com/pushbits/server/internal/pberrors" ) // MessageFormat is a matrix message format @@ -77,7 +77,7 @@ func (d *Dispatcher) DeleteNotification(a *model.Application, n *model.DeleteNot if err != nil { log.Println(err) - return api.ErrorMessageNotFound + return pberrors.ErrorMessageNotFound } oldBody, oldFormattedBody, err = bodiesFromMessage(deleteMessage) @@ -182,7 +182,7 @@ func (d *Dispatcher) getMessage(a *model.Application, id string) (gomatrix.Event } start = messages.End } - return gomatrix.Event{}, api.ErrorMessageNotFound + return gomatrix.Event{}, pberrors.ErrorMessageNotFound } // Replaces the content of a matrix message @@ -254,19 +254,19 @@ func bodiesFromMessage(message gomatrix.Event) (body, formattedBody string, err body, ok := val.(string) if !ok { - return "", "", api.ErrorMessageNotFound + return "", "", pberrors.ErrorMessageNotFound } formattedBody = body } else { - return "", "", api.ErrorMessageNotFound + return "", "", pberrors.ErrorMessageNotFound } if val, ok := message.Content["formatted_body"]; ok { body, ok := val.(string) if !ok { - return "", "", api.ErrorMessageNotFound + return "", "", pberrors.ErrorMessageNotFound } formattedBody = body diff --git a/internal/pberrors/errors.go b/internal/pberrors/errors.go new file mode 100644 index 0000000..ff31d0c --- /dev/null +++ b/internal/pberrors/errors.go @@ -0,0 +1,6 @@ +package pberrors + +import "errors" + +// ErrorMessageNotFound indicates that a message does not exist +var ErrorMessageNotFound = errors.New("message not found") diff --git a/tests/mockups/dispatcher.go b/tests/mockups/dispatcher.go index 6a5b314..b273d39 100644 --- a/tests/mockups/dispatcher.go +++ b/tests/mockups/dispatcher.go @@ -7,11 +7,5 @@ import ( // GetMatrixDispatcher creates and returns a matrix dispatcher func GetMatrixDispatcher(homeserver, username, password string, confCrypto configuration.CryptoConfig) (*dispatcher.Dispatcher, error) { - db, err := GetEmptyDatabase(confCrypto) - - if err != nil { - return nil, err - } - - return dispatcher.Create(db, homeserver, username, password, configuration.Formatting{}) + return dispatcher.Create(homeserver, username, password, configuration.Formatting{}) } From 72671f33d35ef29a292f1106aef792a882a9b862 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:41:58 +0200 Subject: [PATCH 11/15] lower case errors --- tests/mockups/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mockups/config.go b/tests/mockups/config.go index 790d16e..d87ea65 100644 --- a/tests/mockups/config.go +++ b/tests/mockups/config.go @@ -14,12 +14,12 @@ func ReadConfig(filename string, removeFile bool) (config *configuration.Configu defer func() { if r := recover(); r != nil { log.Println(r) - err = errors.New("Paniced while reading config") + err = errors.New("paniced while reading config") } }() if filename == "" { - return nil, errors.New("Empty filename") + return nil, errors.New("empty filename") } file, err := ioutil.ReadFile(filename) From 4c84589172080eca20ea80a4f4303b0816c88e98 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sun, 20 Jun 2021 17:48:04 +0200 Subject: [PATCH 12/15] improve code --- internal/api/application_test.go | 8 ++------ internal/configuration/configuration_test.go | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/api/application_test.go b/internal/api/application_test.go index a09fd75..0306cb2 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -178,7 +178,7 @@ func TestApi_GetApplicationErrors(t *testing.T) { gin.SetMode(gin.TestMode) // Arbitrary test cases - testCases := make(map[uint]tests.Request, 0) + testCases := make(map[uint]tests.Request) testCases[0] = tests.Request{Name: "Requesting unknown application 0", Method: "GET", Endpoint: "/application/0", ShouldStatus: 404} testCases[5555] = tests.Request{Name: "Requesting unknown application 5555", Method: "GET", Endpoint: "/application/5555", ShouldStatus: 404} testCases[99999999999999999] = tests.Request{Name: "Requesting unknown application 99999999999999999", Method: "GET", Endpoint: "/application/99999999999999999", ShouldStatus: 404} @@ -325,11 +325,7 @@ func getApplicationHandler(c *configuration.Configuration) (*ApplicationHandler, // True if all created applications are in list func validateAllApplications(user *model.User, apps []model.Application) bool { if _, ok := SuccessAplications[user.ID]; !ok { - if len(apps) == 0 { - return true - } - - return false + return len(apps) == 0 } for _, successApp := range SuccessAplications[user.ID] { diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go index eebfc04..4aa1e9f 100644 --- a/internal/configuration/configuration_test.go +++ b/internal/configuration/configuration_test.go @@ -20,6 +20,7 @@ type Pair struct { func TestMain(m *testing.M) { m.Run() cleanUp() + os.Exit(0) } func TestConfiguration_GetMinimal(t *testing.T) { From 3ad8a5044e79a2ebf0ea26f36820c8f8b3d21df6 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Mon, 28 Jun 2021 18:56:24 +0200 Subject: [PATCH 13/15] get rid of external data for testing --- README.md | 2 -- internal/api/application_test.go | 18 ++++++++---------- tests/mockups/dispatcher.go | 22 +++++++++++++++++----- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c4cd54c..aeea4e1 100644 --- a/README.md +++ b/README.md @@ -174,8 +174,6 @@ git clone https://github.com/pushbits/server.git Testing is essential for deliviering a good and reliable software. PushBits uses golangs integrated test features. Unfortunately writing tests is quite time consuming and therefore not every feature and every line of code is automatically tested. Feel free to help us improve our tests. -Some tests depend on confidential configuration data. Therefore provide a `config.yml` in PushBits main folder. - To run tests for a single (sub)module you can simply execute the following command in the modules folder. ```bash diff --git a/internal/api/application_test.go b/internal/api/application_test.go index 0306cb2..ad2ba69 100644 --- a/internal/api/application_test.go +++ b/internal/api/application_test.go @@ -26,15 +26,15 @@ var SuccessAplications map[uint][]model.Application func TestMain(m *testing.M) { // Get main config and adapt - config, err := mockups.ReadConfig("../../config.yml", true) - if err != nil { - cleanUp() - log.Println("Can not read config: ", err) - os.Exit(1) - } + config := &configuration.Configuration{} config.Database.Connection = "pushbits-test.db" config.Database.Dialect = "sqlite3" + config.Crypto.Argon2.Iterations = 4 + config.Crypto.Argon2.Parallelism = 4 + config.Crypto.Argon2.Memory = 131072 + config.Crypto.Argon2.SaltLength = 16 + config.Crypto.Argon2.KeyLength = 32 // Set up test environment db, err := mockups.GetEmptyDatabase(config.Crypto) @@ -312,10 +312,8 @@ func TestApi_DeleteApplication(t *testing.T) { // GetApplicationHandler creates and returns an application handler func getApplicationHandler(c *configuration.Configuration) (*ApplicationHandler, error) { - dispatcher, err := mockups.GetMatrixDispatcher(c.Matrix.Homeserver, c.Matrix.Username, c.Matrix.Password, c.Crypto) - if err != nil { - return nil, err - } + dispatcher := &mockups.MockDispatcher{} + return &ApplicationHandler{ DB: TestDatabase, DP: dispatcher, diff --git a/tests/mockups/dispatcher.go b/tests/mockups/dispatcher.go index b273d39..b0accab 100644 --- a/tests/mockups/dispatcher.go +++ b/tests/mockups/dispatcher.go @@ -1,11 +1,23 @@ package mockups import ( - "github.com/pushbits/server/internal/configuration" - "github.com/pushbits/server/internal/dispatcher" + "fmt" + + "github.com/pushbits/server/internal/model" ) -// GetMatrixDispatcher creates and returns a matrix dispatcher -func GetMatrixDispatcher(homeserver, username, password string, confCrypto configuration.CryptoConfig) (*dispatcher.Dispatcher, error) { - return dispatcher.Create(homeserver, username, password, configuration.Formatting{}) +// MockDispatcher is a dispatcher used for testing - it does not need any storage interface +type MockDispatcher struct { +} + +func (d *MockDispatcher) RegisterApplication(id uint, name, token, user string) (string, error) { + return fmt.Sprintf("%d-%s", id, name), nil +} + +func (d *MockDispatcher) DeregisterApplication(a *model.Application, u *model.User) error { + return nil +} + +func (d *MockDispatcher) UpdateApplication(a *model.Application) error { + return nil } From d764733b592ea382dc5cef41172215d2fb9b7da9 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Sat, 3 Jul 2021 15:05:21 +0200 Subject: [PATCH 14/15] remove private file :) --- app/test_notifications.py | 168 -------------------------------------- 1 file changed, 168 deletions(-) delete mode 100644 app/test_notifications.py diff --git a/app/test_notifications.py b/app/test_notifications.py deleted file mode 100644 index c12d5e4..0000000 --- a/app/test_notifications.py +++ /dev/null @@ -1,168 +0,0 @@ -import requests, json - -token = 'AxZTwBZXs2YK1J5IZa0fyCcfHz9cYM9VjaO627eMSbAXAMdwFluGZSOTB4Vk3RHY' - -url = 'https://push.remote.alexanderebhart.de/message?token=' + token -headers = {'content-type': 'application/json'} - -messages = [ - { - "message": "
", - "title": "NEW TEST", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - } - }, - { - "message": "line
break", - "title": "Linebreak single br", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - } - }, - { - "message": "line \n break", - "title": "Linebreak single n", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - } - }, - { - "message": """line - break""", - "title": "Linebreak native", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - } - }, - { - "message": "# Heading 1\n\n###### Heading 6\n\nAlt-H1\n=====\n\n**bold**\n\n_curly_\n\n~~Strike through~~\n\n[Link](google.com)\n\n* list1 \n* list2\n\n1. another list\n2. numerated\n\n![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png)\n\n`some inline code`\n\n```\nA code block\n```\n\n> Blockquote", - "title": "Markdown styling", - "extras": - { - "client::display": - { - "contentType": "text/markdown" - } - } - }, - { - "message": "Red", - "title": "HTML", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - } - }, -] - -priorities = [ - { - "message": "Some text", - "title": "Prio 0", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": 0 - }, - { - "message": "Some text", - "title": "Prio 3", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": 3 - }, - { - "message": "Some text", - "title": "Prio 4", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": 4 - }, - { - "message": "Some text", - "title": "Prio 15", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": 15 - }, - { - "message": "Some text", - "title": "Prio 21", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": 21 - }, - { - "message": "Some text", - "title": "Prio -5", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - "priority": -5 - }, - { - "message": "Some text", - "title": "No Prio", - "extras": - { - "client::display": - { - "contentType": "text/html" - } - }, - - }, -] - - -for data in priorities: - x = requests.post(url, data = json.dumps(data), headers=headers) - print(x.text) \ No newline at end of file From 4e01354c904d814fe8855fe66c3b180472daf967 Mon Sep 17 00:00:00 2001 From: Cubicroot Date: Mon, 5 Jul 2021 19:46:48 +0200 Subject: [PATCH 15/15] move to separate config file for testing --- README.md | 4 ++-- execute_tests.sh | 1 - internal/configuration/configuration.go | 6 ++++++ internal/configuration/configuration_test.go | 13 +++++++------ 4 files changed, 15 insertions(+), 9 deletions(-) delete mode 100644 execute_tests.sh diff --git a/README.md b/README.md index aeea4e1..d8c3ca3 100644 --- a/README.md +++ b/README.md @@ -192,8 +192,8 @@ To execute a single test use the `-run` flag. go test -run "TestApi_getUser" ``` -Running tests for all PushBits module is done by the `execute_tests.sh` script provided. +Running tests for all PushBits module is done like this: ```bash -bash execute_tests.sh +make test ``` \ No newline at end of file diff --git a/execute_tests.sh b/execute_tests.sh deleted file mode 100644 index 863ee90..0000000 --- a/execute_tests.sh +++ /dev/null @@ -1 +0,0 @@ -find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test -cover diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go index 3488b99..5da3653 100644 --- a/internal/configuration/configuration.go +++ b/internal/configuration/configuration.go @@ -4,6 +4,9 @@ import ( "github.com/jinzhu/configor" ) +// testMode indicates if the package is run in test mode +var testMode bool + // Argon2Config holds the parameters used for creating hashes with Argon2. type Argon2Config struct { Memory uint32 `default:"131072"` @@ -55,6 +58,9 @@ type Configuration struct { } func configFiles() []string { + if testMode { + return []string{"config_unittest.yml"} + } return []string{"config.yml"} } diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go index 4aa1e9f..988661a 100644 --- a/internal/configuration/configuration_test.go +++ b/internal/configuration/configuration_test.go @@ -18,6 +18,7 @@ type Pair struct { } func TestMain(m *testing.M) { + testMode = true m.Run() cleanUp() os.Exit(0) @@ -145,7 +146,7 @@ func writeMinimalConfig() error { return err } - return ioutil.WriteFile("config.yml", configString, 0644) + return ioutil.WriteFile("config_unittest.yml", configString, 0644) } // Writes a config with default values to config.yml @@ -159,7 +160,7 @@ func writeValidConfig() error { Environment: "production", ENVPrefix: "PUSHBITS", ErrorOnUnmatchedKeys: true, - }).Load(config, "config.yml") + }).Load(config, "config_unittest.yml") if err != nil { return err } @@ -173,13 +174,13 @@ func writeValidConfig() error { return err } - return ioutil.WriteFile("config.yml", configString, 0644) + return ioutil.WriteFile("config_unittest.yml", configString, 0644) } // Writes a config that is empty func writeEmptyConfig() error { cleanUp() - return ioutil.WriteFile("config.yml", []byte(""), 0644) + return ioutil.WriteFile("config_unittest.yml", []byte(""), 0644) } // Writes a config with invalid entries @@ -196,9 +197,9 @@ func writeInvalidConfig() error { return err } - return ioutil.WriteFile("config.yml", configString, 0644) + return ioutil.WriteFile("config_unittest.yml", configString, 0644) } func cleanUp() error { - return os.Remove("config.yml") + return os.Remove("config_unittest.yml") }