From 489ff0dbadf746f56e499f5614a9bb69a2b1f28b Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 23 Nov 2014 12:12:56 +0100 Subject: [PATCH 01/19] Added some basic tests (that don't work) --- db/setup.go | 1 + env/config.go | 12 ++- main.go | 182 +++++--------------------------------- routes/behavioral_test.go | 132 +++++++++++++++++++++++++++ setup/setup.go | 163 ++++++++++++++++++++++++++++++++++ setup/setup_test.go | 29 ++++++ 6 files changed, 355 insertions(+), 164 deletions(-) create mode 100644 routes/behavioral_test.go create mode 100644 setup/setup.go create mode 100644 setup/setup_test.go diff --git a/db/setup.go b/db/setup.go index 835a146..e3fd1f6 100644 --- a/db/setup.go +++ b/db/setup.go @@ -27,6 +27,7 @@ var databaseNames = []string{ "prod", "staging", "dev", + "test", } // Setup configures the RethinkDB server diff --git a/env/config.go b/env/config.go index 40d8551..880cb12 100644 --- a/env/config.go +++ b/env/config.go @@ -2,9 +2,15 @@ package env // Flags contains values of flags which are important in the whole API type Flags struct { - BindAddress string - APIVersion string - LogFormatterType string + BindAddress string + APIVersion string + LogFormatterType string + ForceColors bool + SessionDuration int ClassicRegistration bool + + RethinkDBURL string + RethinkDBKey string + RethinkDBDatabase string } diff --git a/main.go b/main.go index 1ef2346..8d20261 100644 --- a/main.go +++ b/main.go @@ -4,19 +4,14 @@ import ( "net" "net/http" "os" - "time" "github.com/Sirupsen/logrus" - "github.com/dancannon/gorethink" - "github.com/lavab/glogrus" + "github.com/namsral/flag" "github.com/zenazn/goji/graceful" - "github.com/zenazn/goji/web" - "github.com/zenazn/goji/web/middleware" - "github.com/lavab/api/db" "github.com/lavab/api/env" - "github.com/lavab/api/routes" + "github.com/lavab/api/setup" ) // TODO: "Middleware that implements a few quick security wins" @@ -35,7 +30,7 @@ var ( rethinkdbURL = flag.String("rethinkdb_url", func() string { address := os.Getenv("RETHINKDB_PORT_28015_TCP_ADDR") if address == "" { - address = "localhost" + address = "127.0.0.1" } return address + ":28015" }(), "Address of the RethinkDB database") @@ -55,163 +50,28 @@ func main() { // Put config into the environment package env.Config = &env.Flags{ - BindAddress: *bindAddress, - APIVersion: *apiVersion, - LogFormatterType: *logFormatterType, - SessionDuration: *sessionDuration, - ClassicRegistration: *classicRegistration, - } - - // Set up a new logger - log := logrus.New() + BindAddress: *bindAddress, + APIVersion: *apiVersion, + LogFormatterType: *logFormatterType, + ForceColors: *forceColors, - // Set the formatter depending on the passed flag's value - if *logFormatterType == "text" { - log.Formatter = &logrus.TextFormatter{ - ForceColors: *forceColors, - } - } else if *logFormatterType == "json" { - log.Formatter = &logrus.JSONFormatter{} - } - - // Pass it to the environment package - env.Log = log - - // Set up the database - rethinkOpts := gorethink.ConnectOpts{ - Address: *rethinkdbURL, - AuthKey: *rethinkdbKey, - MaxIdle: 10, - IdleTimeout: time.Second * 10, - } - err := db.Setup(rethinkOpts) - if err != nil { - log.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Unable to set up the database") - } - - // Initialize the actual connection - rethinkOpts.Database = *rethinkdbDatabase - rethinkSession, err := gorethink.Connect(rethinkOpts) - if err != nil { - log.WithFields(logrus.Fields{ - "error": err, - }).Fatal("Unable to connect to the database") - } - - // Put the RethinkDB session into the environment package - env.Rethink = rethinkSession + ClassicRegistration: *classicRegistration, + SessionDuration: *sessionDuration, - // Initialize the tables - env.Tokens = &db.TokensTable{ - RethinkCRUD: db.NewCRUDTable( - rethinkSession, - rethinkOpts.Database, - "tokens", - ), - } - env.Accounts = &db.AccountsTable{ - RethinkCRUD: db.NewCRUDTable( - rethinkSession, - rethinkOpts.Database, - "accounts", - ), - Tokens: env.Tokens, - } - env.Keys = &db.KeysTable{ - RethinkCRUD: db.NewCRUDTable( - rethinkSession, - rethinkOpts.Database, - "keys", - ), - } - env.Contacts = &db.ContactsTable{ - RethinkCRUD: db.NewCRUDTable( - rethinkSession, - rethinkOpts.Database, - "contacts", - ), + RethinkDBURL: *rethinkdbURL, + RethinkDBKey: *rethinkdbKey, + RethinkDBDatabase: *rethinkdbDatabase, } - // Create a new goji mux - mux := web.New() - - // Include the most basic middlewares: - // - RequestID assigns an unique ID for each request in order to identify errors. - // - Glogrus logs each request - // - Recoverer prevents panics from crashing the API - // - AutomaticOptions automatically responds to OPTIONS requests - mux.Use(middleware.RequestID) - mux.Use(glogrus.NewGlogrus(log, "api")) - mux.Use(middleware.Recoverer) - mux.Use(middleware.AutomaticOptions) - - // Set up an auth'd mux - auth := web.New() - auth.Use(routes.AuthMiddleware) - - // Index route - mux.Get("/", routes.Hello) - - // Accounts - auth.Get("/accounts", routes.AccountsList) - mux.Post("/accounts", routes.AccountsCreate) - auth.Get("/accounts/:id", routes.AccountsGet) - auth.Put("/accounts/:id", routes.AccountsUpdate) - auth.Delete("/accounts/:id", routes.AccountsDelete) - auth.Post("/accounts/:id/wipe-data", routes.AccountsWipeData) - - // Tokens - auth.Get("/tokens", routes.TokensGet) - mux.Post("/tokens", routes.TokensCreate) - auth.Delete("/tokens", routes.TokensDelete) - auth.Delete("/tokens/:id", routes.TokensDelete) - - // Threads - auth.Get("/threads", routes.ThreadsList) - auth.Get("/threads/:id", routes.ThreadsGet) - auth.Put("/threads/:id", routes.ThreadsUpdate) - - // Emails - auth.Get("/emails", routes.EmailsList) - auth.Post("/emails", routes.EmailsCreate) - auth.Get("/emails/:id", routes.EmailsGet) - auth.Put("/emails/:id", routes.EmailsUpdate) - auth.Delete("/emails/:id", routes.EmailsDelete) - - // Labels - auth.Get("/labels", routes.LabelsList) - auth.Post("/labels", routes.LabelsCreate) - auth.Get("/labels/:id", routes.LabelsGet) - auth.Put("/labels/:id", routes.LabelsUpdate) - auth.Delete("/labels/:id", routes.LabelsDelete) - - // Contacts - auth.Get("/contacts", routes.ContactsList) - auth.Post("/contacts", routes.ContactsCreate) - auth.Get("/contacts/:id", routes.ContactsGet) - auth.Put("/contacts/:id", routes.ContactsUpdate) - auth.Delete("/contacts/:id", routes.ContactsDelete) - - // Keys - mux.Get("/keys", routes.KeysList) - auth.Post("/keys", routes.KeysCreate) - mux.Get("/keys/:id", routes.KeysGet) - auth.Post("/keys/:id/vote", routes.KeysVote) - - // Merge the muxes - mux.Handle("/*", auth) - - // Compile the routes - mux.Compile() + // Generate a mux + mux := setup.PrepareMux(env.Config) // Make the mux handle every request http.Handle("/", mux) // Log that we're starting the server - log.WithFields(logrus.Fields{ - "address": *bindAddress, + env.Log.WithFields(logrus.Fields{ + "address": env.Config.BindAddress, }).Info("Starting the HTTP server") // Initialize the goroutine listening to signals passed to the app @@ -219,18 +79,18 @@ func main() { // Pre-graceful shutdown event graceful.PreHook(func() { - log.Info("Received a singnal, stopping the application") + env.Log.Info("Received a singnal, stopping the application") }) // Post-shutdown event graceful.PostHook(func() { - log.Info("Stopped the application") + env.Log.Info("Stopped the application") }) // Listen to the passed address - listener, err := net.Listen("tcp", *bindAddress) + listener, err := net.Listen("tcp", env.Config.BindAddress) if err != nil { - log.WithFields(logrus.Fields{ + env.Log.WithFields(logrus.Fields{ "error": err, "address": *bindAddress, }).Fatal("Cannot set up a TCP listener") @@ -240,7 +100,7 @@ func main() { err = graceful.Serve(listener, http.DefaultServeMux) if err != nil { // Don't use .Fatal! We need the code to shut down properly. - log.Error(err) + env.Log.Error(err) } // If code reaches this place, it means that it was forcefully closed. diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go new file mode 100644 index 0000000..2ddee99 --- /dev/null +++ b/routes/behavioral_test.go @@ -0,0 +1,132 @@ +package routes_test + +import ( + "net/http/httptest" + "testing" + "time" + + "github.com/dancannon/gorethink" + "github.com/franela/goreq" + "github.com/gyepisam/mcf" + _ "github.com/gyepisam/mcf/scrypt" + "github.com/stretchr/testify/assert" + + "github.com/lavab/api/env" + "github.com/lavab/api/models" + "github.com/lavab/api/routes" + "github.com/lavab/api/setup" +) + +var ( + server *httptest.Server +) + +func init() { + // Mock data + env.Config = &env.Flags{ + APIVersion: "v0", + LogFormatterType: "text", + ForceColors: false, + + SessionDuration: 72, + ClassicRegistration: true, + + RethinkDBURL: "127.0.0.1:28015", + RethinkDBKey: "", + RethinkDBDatabase: "test", + } + + // Connect to the RethinkDB server + rdbSession, err := gorethink.Connect(gorethink.ConnectOpts{ + Address: env.Config.RethinkDBURL, + AuthKey: env.Config.RethinkDBKey, + MaxIdle: 10, + IdleTimeout: time.Second * 10, + }) + if err != nil { + panic("connecting to RethinkDB should not return an error, got " + err.Error()) + } + + // Clear the test database + err = gorethink.DbDrop("test").Exec(rdbSession) + if err != nil { + panic("removing the test database should not return an error, got " + err.Error()) + } + + // Disconnect + err = rdbSession.Close() + if err != nil { + panic("closing the RethinkDB session should not return an error, got " + err.Error()) + } + + // Prepare a new mux (initialize the API) + mux := setup.PrepareMux(env.Config) + if mux == nil { + panic("returned mux was nil") + } + + // Set up a new temporary HTTP test server + server = httptest.NewServer(mux) + if server == nil { + panic("returned httptest server was nil") + } +} + +func TestHello(t *testing.T) { + // Request the / route + helloResult, err := goreq.Request{ + Method: "GET", + Uri: server.URL, + }.Do() + assert.Nil(t, err, "requesting / should not return an error") + + // Unmarshal the response + var helloResponse routes.HelloResponse + err = helloResult.Body.FromJsonTo(&helloResponse) + assert.Nil(t, err, "unmarshaling / result should not return an error") + assert.Equal(t, "Lavaboom API", helloResponse.Message) +} + +func TestAccounts(t *testing.T) { + // Constants for input data + const ( + usernameInvited = "jeremy" + passwordInvited = "potato" + ) + + // Hash the passwords + passwordClassicHashed, err := mcf.Create(passwordInvited) + assert.Nil(t, err, "hashing passwordInvited should not return an error") + + // Prepare a token + inviteToken := models.Token{ + Resource: models.MakeResource("", "test invite token"), + Type: "invite", + } + err = env.Tokens.Insert(inviteToken) + assert.Nil(t, err, "inserting a new invitation token should not return an error") + + // POST /accounts - invited + createInvitedResult, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + Body: routes.AccountsCreateRequest{ + Username: usernameInvited, + Password: passwordClassicHashed, + Token: inviteToken.ID, + }, + }.Do() + + x, _ := createInvitedResult.Body.ToString() + env.Log.Print(x) + + // Unmarshal the response + var createInvitedResponse routes.AccountsCreateResponse + err = createInvitedResult.Body.FromJsonTo(&createInvitedResponse) + assert.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + assert.True(t, createInvitedResponse.Success, "creating a new account using inv registration failed") + assert.Equal(t, "A new account was successfully created", createInvitedResponse.Message, "invalid message returned by invited acc creation") + assert.NotEmpty(t, createInvitedResponse.Account.ID, "newly created account's id should not be empty") +} diff --git a/setup/setup.go b/setup/setup.go new file mode 100644 index 0000000..ddbfabe --- /dev/null +++ b/setup/setup.go @@ -0,0 +1,163 @@ +package setup + +import ( + "time" + + "github.com/Sirupsen/logrus" + "github.com/dancannon/gorethink" + "github.com/goji/glogrus" + "github.com/zenazn/goji/web" + "github.com/zenazn/goji/web/middleware" + + "github.com/lavab/api/db" + "github.com/lavab/api/env" + "github.com/lavab/api/routes" +) + +func PrepareMux(flags *env.Flags) *web.Mux { + // Set up a new logger + log := logrus.New() + + // Set the formatter depending on the passed flag's value + if flags.LogFormatterType == "text" { + log.Formatter = &logrus.TextFormatter{ + ForceColors: flags.ForceColors, + } + } else if flags.LogFormatterType == "json" { + log.Formatter = &logrus.JSONFormatter{} + } + + // Pass it to the environment package + env.Log = log + + // Set up the database + rethinkOpts := gorethink.ConnectOpts{ + Address: flags.RethinkDBURL, + AuthKey: flags.RethinkDBKey, + MaxIdle: 10, + IdleTimeout: time.Second * 10, + } + err := db.Setup(rethinkOpts) + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + }).Fatal("Unable to set up the database") + } + + // Initialize the actual connection + rethinkOpts.Database = flags.RethinkDBDatabase + rethinkSession, err := gorethink.Connect(rethinkOpts) + if err != nil { + log.WithFields(logrus.Fields{ + "error": err, + }).Fatal("Unable to connect to the database") + } + + // Put the RethinkDB session into the environment package + env.Rethink = rethinkSession + + // Initialize the tables + env.Tokens = &db.TokensTable{ + RethinkCRUD: db.NewCRUDTable( + rethinkSession, + rethinkOpts.Database, + "tokens", + ), + } + env.Accounts = &db.AccountsTable{ + RethinkCRUD: db.NewCRUDTable( + rethinkSession, + rethinkOpts.Database, + "accounts", + ), + Tokens: env.Tokens, + } + env.Keys = &db.KeysTable{ + RethinkCRUD: db.NewCRUDTable( + rethinkSession, + rethinkOpts.Database, + "keys", + ), + } + env.Contacts = &db.ContactsTable{ + RethinkCRUD: db.NewCRUDTable( + rethinkSession, + rethinkOpts.Database, + "contacts", + ), + } + + // Create a new goji mux + mux := web.New() + + // Include the most basic middlewares: + // - RequestID assigns an unique ID for each request in order to identify errors. + // - Glogrus logs each request + // - Recoverer prevents panics from crashing the API + // - AutomaticOptions automatically responds to OPTIONS requests + mux.Use(middleware.RequestID) + mux.Use(glogrus.NewGlogrus(log, "api")) + mux.Use(middleware.Recoverer) + mux.Use(middleware.AutomaticOptions) + + // Set up an auth'd mux + auth := web.New() + auth.Use(routes.AuthMiddleware) + + // Index route + mux.Get("/", routes.Hello) + + // Accounts + auth.Get("/accounts", routes.AccountsList) + mux.Post("/accounts", routes.AccountsCreate) + auth.Get("/accounts/:id", routes.AccountsGet) + auth.Put("/accounts/:id", routes.AccountsUpdate) + auth.Delete("/accounts/:id", routes.AccountsDelete) + auth.Post("/accounts/:id/wipe-data", routes.AccountsWipeData) + + // Tokens + auth.Get("/tokens", routes.TokensGet) + mux.Post("/tokens", routes.TokensCreate) + auth.Delete("/tokens", routes.TokensDelete) + auth.Delete("/tokens/:id", routes.TokensDelete) + + // Threads + auth.Get("/threads", routes.ThreadsList) + auth.Get("/threads/:id", routes.ThreadsGet) + auth.Put("/threads/:id", routes.ThreadsUpdate) + + // Emails + auth.Get("/emails", routes.EmailsList) + auth.Post("/emails", routes.EmailsCreate) + auth.Get("/emails/:id", routes.EmailsGet) + auth.Put("/emails/:id", routes.EmailsUpdate) + auth.Delete("/emails/:id", routes.EmailsDelete) + + // Labels + auth.Get("/labels", routes.LabelsList) + auth.Post("/labels", routes.LabelsCreate) + auth.Get("/labels/:id", routes.LabelsGet) + auth.Put("/labels/:id", routes.LabelsUpdate) + auth.Delete("/labels/:id", routes.LabelsDelete) + + // Contacts + auth.Get("/contacts", routes.ContactsList) + auth.Post("/contacts", routes.ContactsCreate) + auth.Get("/contacts/:id", routes.ContactsGet) + auth.Put("/contacts/:id", routes.ContactsUpdate) + auth.Delete("/contacts/:id", routes.ContactsDelete) + + // Keys + mux.Get("/keys", routes.KeysList) + auth.Post("/keys", routes.KeysCreate) + mux.Get("/keys/:id", routes.KeysGet) + auth.Post("/keys/:id/vote", routes.KeysVote) + + // Merge the muxes + mux.Handle("/*", auth) + + // Compile the routes + mux.Compile() + + return mux +} diff --git a/setup/setup_test.go b/setup/setup_test.go new file mode 100644 index 0000000..3c90daa --- /dev/null +++ b/setup/setup_test.go @@ -0,0 +1,29 @@ +package setup + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/lavab/api/env" +) + +func TestSetup(t *testing.T) { + // Mock data + env.Config = &env.Flags{ + APIVersion: "v0", + LogFormatterType: "text", + ForceColors: false, + + SessionDuration: 72, + ClassicRegistration: true, + + RethinkDBURL: "127.0.0.1:28015", + RethinkDBKey: "", + RethinkDBDatabase: "test", + } + + // Prepare a new mux (initialize the API) + mux := PrepareMux(env.Config) + assert.NotNil(t, mux, "mux should not be nil") +} From 909c7b8a574838ff7acb2ddbaa67e06ba1394cbe Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 23 Nov 2014 12:24:15 +0100 Subject: [PATCH 02/19] Fixed tests, added application/json as content-type for post requests --- routes/accounts.go | 10 +++++----- routes/behavioral_test.go | 29 ++++++++++++++--------------- setup/setup_test.go | 4 ++-- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/routes/accounts.go b/routes/accounts.go index eaf9618..ffc138f 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -27,10 +27,10 @@ func AccountsList(w http.ResponseWriter, r *http.Request) { // AccountsCreateRequest contains the input for the AccountsCreate endpoint. type AccountsCreateRequest struct { - Token string `json:"token" schema:"token"` - Username string `json:"username" schema:"username"` - Password string `json:"password" schema:"password"` - AltEmail string `json:"alt_email" schema:"alt_email"` + Token string `json:"token,omitempty" schema:"token"` + Username string `json:"username,omitempty" schema:"username"` + Password string `json:"password,omitempty" schema:"password"` + AltEmail string `json:"alt_email,omitempty" schema:"alt_email"` } // AccountsCreateResponse contains the output of the AccountsCreate request. @@ -71,7 +71,7 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { } // "unknown" requests are empty and invalid - if requestType == "invalid" { + if requestType == "unknown" { utils.JSONResponse(w, 400, &AccountsCreateResponse{ Success: false, Message: "Invalid request", diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 2ddee99..47956a4 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -9,7 +9,7 @@ import ( "github.com/franela/goreq" "github.com/gyepisam/mcf" _ "github.com/gyepisam/mcf/scrypt" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/lavab/api/env" "github.com/lavab/api/models" @@ -78,13 +78,13 @@ func TestHello(t *testing.T) { Method: "GET", Uri: server.URL, }.Do() - assert.Nil(t, err, "requesting / should not return an error") + require.Nil(t, err, "requesting / should not return an error") // Unmarshal the response var helloResponse routes.HelloResponse err = helloResult.Body.FromJsonTo(&helloResponse) - assert.Nil(t, err, "unmarshaling / result should not return an error") - assert.Equal(t, "Lavaboom API", helloResponse.Message) + require.Nil(t, err, "unmarshaling / result should not return an error") + require.Equal(t, "Lavaboom API", helloResponse.Message) } func TestAccounts(t *testing.T) { @@ -96,37 +96,36 @@ func TestAccounts(t *testing.T) { // Hash the passwords passwordClassicHashed, err := mcf.Create(passwordInvited) - assert.Nil(t, err, "hashing passwordInvited should not return an error") + require.Nil(t, err, "hashing passwordInvited should not return an error") // Prepare a token inviteToken := models.Token{ Resource: models.MakeResource("", "test invite token"), Type: "invite", } + inviteToken.ExpireSoon() err = env.Tokens.Insert(inviteToken) - assert.Nil(t, err, "inserting a new invitation token should not return an error") + require.Nil(t, err, "inserting a new invitation token should not return an error") // POST /accounts - invited createInvitedResult, err := goreq.Request{ - Method: "POST", - Uri: server.URL + "/accounts", + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", Body: routes.AccountsCreateRequest{ Username: usernameInvited, Password: passwordClassicHashed, Token: inviteToken.ID, }, }.Do() - - x, _ := createInvitedResult.Body.ToString() - env.Log.Print(x) // Unmarshal the response var createInvitedResponse routes.AccountsCreateResponse err = createInvitedResult.Body.FromJsonTo(&createInvitedResponse) - assert.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err, "unmarshaling invited account creation should not return an error") // Check the result's contents - assert.True(t, createInvitedResponse.Success, "creating a new account using inv registration failed") - assert.Equal(t, "A new account was successfully created", createInvitedResponse.Message, "invalid message returned by invited acc creation") - assert.NotEmpty(t, createInvitedResponse.Account.ID, "newly created account's id should not be empty") + require.True(t, createInvitedResponse.Success, "creating a new account using inv registration failed") + require.Equal(t, "A new account was successfully created", createInvitedResponse.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, createInvitedResponse.Account.ID, "newly created account's id should not be empty") } diff --git a/setup/setup_test.go b/setup/setup_test.go index 3c90daa..b9e19b6 100644 --- a/setup/setup_test.go +++ b/setup/setup_test.go @@ -3,7 +3,7 @@ package setup import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/lavab/api/env" ) @@ -25,5 +25,5 @@ func TestSetup(t *testing.T) { // Prepare a new mux (initialize the API) mux := PrepareMux(env.Config) - assert.NotNil(t, mux, "mux should not be nil") + require.NotNil(t, mux, "mux should not be nil") } From 4e711b32540751501ebe1f2d5d705e4b6fccfc3f Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 23 Nov 2014 12:44:45 +0100 Subject: [PATCH 03/19] Added tests for classic registration, fixed an issue in the request type detector in accounts.go --- routes/accounts.go | 2 +- routes/behavioral_test.go | 52 ++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/routes/accounts.go b/routes/accounts.go index ffc138f..0a97679 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -64,7 +64,7 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { requestType := "unknown" if input.AltEmail == "" && input.Username != "" && input.Password != "" && input.Token != "" { requestType = "invited" - } else if input.AltEmail != "" && input.Username != "" && input.Password != "" && input.Token != "" { + } else if input.AltEmail != "" && input.Username != "" && input.Password != "" && input.Token == "" { requestType = "classic" } else if input.AltEmail != "" && input.Username == "" && input.Password == "" && input.Token == "" { requestType = "queue" diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 47956a4..43e5954 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -90,13 +90,13 @@ func TestHello(t *testing.T) { func TestAccounts(t *testing.T) { // Constants for input data const ( - usernameInvited = "jeremy" - passwordInvited = "potato" + username = "jeremy" + password = "potato" ) // Hash the passwords - passwordClassicHashed, err := mcf.Create(passwordInvited) - require.Nil(t, err, "hashing passwordInvited should not return an error") + passwordHashed, err := mcf.Create(password) + require.Nil(t, err, "hashing password should not return an error") // Prepare a token inviteToken := models.Token{ @@ -107,17 +107,34 @@ func TestAccounts(t *testing.T) { err = env.Tokens.Insert(inviteToken) require.Nil(t, err, "inserting a new invitation token should not return an error") + // POST /accounts - unknown + createUnknownResult, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + }.Do() + require.Nil(t, err, "querying unknown /accounts should not return an error") + + // Unmarshal the response + var createUnknownResponse routes.AccountsCreateResponse + err = createUnknownResult.Body.FromJsonTo(&createUnknownResponse) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check values + require.False(t, createUnknownResponse.Success, "unknown request should return success false") + require.Equal(t, "Invalid request", createUnknownResponse.Message, "unknown request should return proper error msg") + // POST /accounts - invited createInvitedResult, err := goreq.Request{ Method: "POST", Uri: server.URL + "/accounts", ContentType: "application/json", Body: routes.AccountsCreateRequest{ - Username: usernameInvited, - Password: passwordClassicHashed, + Username: username + "invited", + Password: passwordHashed, Token: inviteToken.ID, }, }.Do() + require.Nil(t, err, "querying invited /accounts should not return an error") // Unmarshal the response var createInvitedResponse routes.AccountsCreateResponse @@ -128,4 +145,27 @@ func TestAccounts(t *testing.T) { require.True(t, createInvitedResponse.Success, "creating a new account using inv registration failed") require.Equal(t, "A new account was successfully created", createInvitedResponse.Message, "invalid message returned by invited acc creation") require.NotEmpty(t, createInvitedResponse.Account.ID, "newly created account's id should not be empty") + + // POST /accounts - classic + createClassicResult, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username + "classic", + Password: passwordHashed, + AltEmail: "something@example.com", + }, + }.Do() + require.Nil(t, err, "querying invited /accounts should not return an error") + + // Unmarshal the response + var createClassicResponse routes.AccountsCreateResponse + err = createClassicResult.Body.FromJsonTo(&createClassicResponse) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.True(t, createClassicResponse.Success, "creating a new account using classic registration failed") + require.Equal(t, "A new account was successfully created, you should receive a confirmation email soon™.", createClassicResponse.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, createClassicResponse.Account.ID, "newly created account's id should not be empty") } From f96145c9e00f6b9c6c4280336339d16d07a14feb Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 23 Nov 2014 18:50:12 +0100 Subject: [PATCH 04/19] Logging in test --- routes/behavioral_test.go | 118 ++++++++++++++++++++++++++++---------- setup/setup.go | 2 +- setup/setup_test.go | 2 +- 3 files changed, 90 insertions(+), 32 deletions(-) diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 43e5954..9328ae5 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -7,7 +7,6 @@ import ( "github.com/dancannon/gorethink" "github.com/franela/goreq" - "github.com/gyepisam/mcf" _ "github.com/gyepisam/mcf/scrypt" "github.com/stretchr/testify/require" @@ -26,7 +25,7 @@ func init() { env.Config = &env.Flags{ APIVersion: "v0", LogFormatterType: "text", - ForceColors: false, + ForceColors: true, SessionDuration: 72, ClassicRegistration: true, @@ -87,64 +86,91 @@ func TestHello(t *testing.T) { require.Equal(t, "Lavaboom API", helloResponse.Message) } -func TestAccounts(t *testing.T) { - // Constants for input data +func TestAccountsCreateUnknown(t *testing.T) { + // POST /accounts - unknown + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + }.Do() + require.Nil(t, err, "querying unknown /accounts should not return an error") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check values + require.False(t, response.Success, "unknown request should return success false") + require.Equal(t, "Invalid request", response.Message, "unknown request should return proper error msg") +} + +func TestAccountsCreateInvited(t *testing.T) { const ( username = "jeremy" password = "potato" ) - // Hash the passwords - passwordHashed, err := mcf.Create(password) - require.Nil(t, err, "hashing password should not return an error") - // Prepare a token inviteToken := models.Token{ Resource: models.MakeResource("", "test invite token"), Type: "invite", } inviteToken.ExpireSoon() - err = env.Tokens.Insert(inviteToken) + + err := env.Tokens.Insert(inviteToken) require.Nil(t, err, "inserting a new invitation token should not return an error") - // POST /accounts - unknown - createUnknownResult, err := goreq.Request{ - Method: "POST", - Uri: server.URL + "/accounts", + // POST /accounts - invited + result1, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, }.Do() - require.Nil(t, err, "querying unknown /accounts should not return an error") + require.Nil(t, err, "querying invited /accounts should not return an error") // Unmarshal the response - var createUnknownResponse routes.AccountsCreateResponse - err = createUnknownResult.Body.FromJsonTo(&createUnknownResponse) + var response1 routes.AccountsCreateResponse + err = result1.Body.FromJsonTo(&response1) require.Nil(t, err, "unmarshaling invited account creation should not return an error") - // Check values - require.False(t, createUnknownResponse.Success, "unknown request should return success false") - require.Equal(t, "Invalid request", createUnknownResponse.Message, "unknown request should return proper error msg") + // Check the result's contents + require.True(t, response1.Success, "creating a new account using inv registration failed") + require.Equal(t, "A new account was successfully created", response1.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, response1.Account.ID, "newly created account's id should not be empty") - // POST /accounts - invited - createInvitedResult, err := goreq.Request{ + // POST /accounts - invited with wrong token + result2, err := goreq.Request{ Method: "POST", Uri: server.URL + "/accounts", ContentType: "application/json", Body: routes.AccountsCreateRequest{ - Username: username + "invited", - Password: passwordHashed, - Token: inviteToken.ID, + Username: username + "2", + Password: password, + Token: "asdasdasd", }, }.Do() require.Nil(t, err, "querying invited /accounts should not return an error") // Unmarshal the response - var createInvitedResponse routes.AccountsCreateResponse - err = createInvitedResult.Body.FromJsonTo(&createInvitedResponse) + var response2 routes.AccountsCreateResponse + err = result2.Body.FromJsonTo(&response2) require.Nil(t, err, "unmarshaling invited account creation should not return an error") // Check the result's contents - require.True(t, createInvitedResponse.Success, "creating a new account using inv registration failed") - require.Equal(t, "A new account was successfully created", createInvitedResponse.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, createInvitedResponse.Account.ID, "newly created account's id should not be empty") + require.False(t, response2.Success, "creating a new account using invalid token should fail") + require.Equal(t, "Invalid invitation token", response2.Message, "invalid message returned by invalid token acc creation") +} + +func TestAccountsCreateClassic(t *testing.T) { + const ( + username = "jeremy_was_invited" + password = "potato" + ) // POST /accounts - classic createClassicResult, err := goreq.Request{ @@ -153,7 +179,7 @@ func TestAccounts(t *testing.T) { ContentType: "application/json", Body: routes.AccountsCreateRequest{ Username: username + "classic", - Password: passwordHashed, + Password: password, AltEmail: "something@example.com", }, }.Do() @@ -169,3 +195,35 @@ func TestAccounts(t *testing.T) { require.Equal(t, "A new account was successfully created, you should receive a confirmation email soon™.", createClassicResponse.Message, "invalid message returned by invited acc creation") require.NotEmpty(t, createClassicResponse.Account.ID, "newly created account's id should not be empty") } + +func TestTokensCreate(t *testing.T) { + // log in as mr jeremy potato + const ( + username = "jeremy" + password = "potato" + ) + // POST /accounts - classic + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Username: username, + Password: password, + Type: "auth", + }, + }.Do() + require.Nil(t, err, "querying existing /tokens should not return an error") + + // Unmarshal the response + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + env.Log.Print(response.Message) + + // Check the result's contents + require.True(t, response.Success, "creating a new token using existing account failed") + require.Equal(t, "Authentication successful", response.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, response.Token.ID, "newly created token's id should not be empty") +} diff --git a/setup/setup.go b/setup/setup.go index ddbfabe..c521f78 100644 --- a/setup/setup.go +++ b/setup/setup.go @@ -5,13 +5,13 @@ import ( "github.com/Sirupsen/logrus" "github.com/dancannon/gorethink" - "github.com/goji/glogrus" "github.com/zenazn/goji/web" "github.com/zenazn/goji/web/middleware" "github.com/lavab/api/db" "github.com/lavab/api/env" "github.com/lavab/api/routes" + "github.com/lavab/glogrus" ) func PrepareMux(flags *env.Flags) *web.Mux { diff --git a/setup/setup_test.go b/setup/setup_test.go index b9e19b6..ebbe49b 100644 --- a/setup/setup_test.go +++ b/setup/setup_test.go @@ -13,7 +13,7 @@ func TestSetup(t *testing.T) { env.Config = &env.Flags{ APIVersion: "v0", LogFormatterType: "text", - ForceColors: false, + ForceColors: true, SessionDuration: 72, ClassicRegistration: true, From daa750dae3bb921442d12ce4c141affb7cd7fda7 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 09:45:16 +0100 Subject: [PATCH 05/19] Added accounts test --- routes/behavioral_test.go | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 9328ae5..559f2cc 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -17,7 +17,8 @@ import ( ) var ( - server *httptest.Server + server *httptest.Server + authToken string ) func init() { @@ -220,10 +221,31 @@ func TestTokensCreate(t *testing.T) { err = request.Body.FromJsonTo(&response) require.Nil(t, err, "unmarshaling invited account creation should not return an error") - env.Log.Print(response.Message) - // Check the result's contents require.True(t, response.Success, "creating a new token using existing account failed") require.Equal(t, "Authentication successful", response.Message, "invalid message returned by invited acc creation") require.NotEmpty(t, response.Token.ID, "newly created token's id should not be empty") + + // Populate the global token variable + authToken = response.Token.ID +} + +func TestAccountsGetMe(t *testing.T) { + // GET /accounts/me + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/me", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "querying /accounts/me should not return an error") + + // Unmarshal the response + var response routes.AccountsGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling /accounts/me should not return an error") + + // Check the result's contents + require.True(t, response.Success, "getting /accounts/me should succeed") + require.Equal(t, "jeremy", response.User.Name, "username should be the previously registered one") } From 1497d4ab7ea6167f14f8320b34a0e8129943f291 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 10:16:38 +0100 Subject: [PATCH 06/19] Added acconts update test --- routes/accounts.go | 29 +++++++++++++++-------------- routes/behavioral_test.go | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/routes/accounts.go b/routes/accounts.go index 0a97679..da077a3 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -222,7 +222,7 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { type AccountsGetResponse struct { Success bool `json:"success"` Message string `json:"message,omitempty"` - User *models.Account `json:"user,omitempty"` + Account *models.Account `json:"user,omitempty"` } // AccountsGet returns the information about the specified account @@ -280,13 +280,12 @@ func AccountsGet(c web.C, w http.ResponseWriter, r *http.Request) { // Return the user struct utils.JSONResponse(w, 200, &AccountsGetResponse{ Success: true, - User: user, + Account: user, }) } // AccountsUpdateRequest contains the input for the AccountsUpdate endpoint. type AccountsUpdateRequest struct { - Type string `json:"type" schema:"type"` AltEmail string `json:"alt_email" schema:"alt_email"` CurrentPassword string `json:"current_password" schema:"current_password"` NewPassword string `json:"new_password" schema:"new_password"` @@ -374,17 +373,19 @@ func AccountsUpdate(c web.C, w http.ResponseWriter, r *http.Request) { return } - err = user.SetPassword(input.NewPassword) - if err != nil { - env.Log.WithFields(logrus.Fields{ - "error": err, - }).Error("Unable to hash a password") + if input.NewPassword != "" { + err = user.SetPassword(input.NewPassword) + if err != nil { + env.Log.WithFields(logrus.Fields{ + "error": err, + }).Error("Unable to hash a password") - utils.JSONResponse(w, 500, &AccountsUpdateResponse{ - Success: false, - Message: "Internal error (code AC/UP/01)", - }) - return + utils.JSONResponse(w, 500, &AccountsUpdateResponse{ + Success: false, + Message: "Internal error (code AC/UP/01)", + }) + return + } } if input.AltEmail != "" { @@ -405,7 +406,7 @@ func AccountsUpdate(c web.C, w http.ResponseWriter, r *http.Request) { } utils.JSONResponse(w, 200, &AccountsUpdateResponse{ - Success: false, + Success: true, Message: "Your account has been successfully updated", Account: user, }) diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 559f2cc..450129e 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -7,7 +7,6 @@ import ( "github.com/dancannon/gorethink" "github.com/franela/goreq" - _ "github.com/gyepisam/mcf/scrypt" "github.com/stretchr/testify/require" "github.com/lavab/api/env" @@ -247,5 +246,36 @@ func TestAccountsGetMe(t *testing.T) { // Check the result's contents require.True(t, response.Success, "getting /accounts/me should succeed") - require.Equal(t, "jeremy", response.User.Name, "username should be the previously registered one") + require.Equal(t, "jeremy", response.Account.Name, "username should be the previously registered one") +} + +func TestAccountUpdateMe(t *testing.T) { + // PUT /accounts/me + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/accounts/me", + ContentType: "application/json", + Body: &routes.AccountsUpdateRequest{ + CurrentPassword: "potato", + NewPassword: "cabbage", + AltEmail: "john.cabbage@example.com", + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "updating account should not return an error") + + // Unmarshal the response + var response routes.AccountsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account update response should not return an error") + + // Check the result's contents + require.Equal(t, "Your account has been successfully updated", response.Message, "response message should be valid") + require.True(t, response.Success, "updating /accounts/me should succeed") + require.Equal(t, "jeremy", response.Account.Name, "username should not be changed") + require.Equal(t, "john.cabbage@example.com", response.Account.AltEmail, "alt email should be changed") + //valid, _, err := response.Account.VerifyPassword("cabbage") + //require.Nil(t, err, "verifying the password should not return an error") + //require.True(t, valid, "password should be changed") } From b3ae3544e259c01bc69ee2796c304538c6150f7c Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 11:46:15 +0100 Subject: [PATCH 07/19] Added tests for delete and wipe --- routes/behavioral_test.go | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/routes/behavioral_test.go b/routes/behavioral_test.go index 450129e..102583a 100644 --- a/routes/behavioral_test.go +++ b/routes/behavioral_test.go @@ -17,6 +17,7 @@ import ( var ( server *httptest.Server + accountID string authToken string ) @@ -143,6 +144,8 @@ func TestAccountsCreateInvited(t *testing.T) { require.Equal(t, "A new account was successfully created", response1.Message, "invalid message returned by invited acc creation") require.NotEmpty(t, response1.Account.ID, "newly created account's id should not be empty") + accountID = response1.Account.ID + // POST /accounts - invited with wrong token result2, err := goreq.Request{ Method: "POST", @@ -279,3 +282,53 @@ func TestAccountUpdateMe(t *testing.T) { //require.Nil(t, err, "verifying the password should not return an error") //require.True(t, valid, "password should be changed") } + +func TestAccountsWipeData(t *testing.T) { + // POST /accounts/me/wipe-data + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts/me/wipe-data", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "wiping account should not return an error") + + // Unmarshal the response + var response routes.AccountsWipeDataResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account wipe response should not return an error") + + // Check the result's contents + require.Equal(t, "Your account has been successfully wiped", response.Message, "response message should be valid") + require.True(t, response.Success, "triggering /accounts/wipe-data should succeed") +} + +func TestAccountsDelete(t *testing.T) { + // Prepare a token + token := models.Token{ + Resource: models.MakeResource(accountID, "test invite token"), + Type: "auth", + } + token.ExpireSoon() + + err := env.Tokens.Insert(token) + require.Nil(t, err, "inserting a new auth toekn token should not return an error") + + // DELETE /accounts/me + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/accounts/me", + } + request.AddHeader("Authorization", "Bearer "+token.ID) + result, err := request.Do() + require.Nil(t, err, "deleting account should not return an error") + + // Unmarshal the response + var response routes.AccountsWipeDataResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account delete response should not return an error") + + // Check the result's contents + require.Equal(t, "Your account has been successfully deleted", response.Message, "response message should be valid") + require.True(t, response.Success, "triggering delete /account/me should succeed") +} From d859ad1b4d232f479463b656db7f0e52fc27ea3b Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 14:00:43 +0100 Subject: [PATCH 08/19] Adding rethinkdb to tests --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a7db419..075f191 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,10 @@ language: go go: - - 1.3.1 \ No newline at end of file + - 1.3.1 + +before_script: + - sudo add-apt-repository ppa:rethinkdb/ppa -y + - sudo apt-get update -q + - sudo apt-get install rethinkdb + - rethinkdb --bind all & From 6527077835c9a9be870d1db143caa26d5784f8ec Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 14:03:11 +0100 Subject: [PATCH 09/19] Adding froce-yes to the build script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 075f191..dc770e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,5 @@ go: before_script: - sudo add-apt-repository ppa:rethinkdb/ppa -y - sudo apt-get update -q - - sudo apt-get install rethinkdb + - sudo apt-get install --force-yes rethinkdb - rethinkdb --bind all & From 1c4735389b9129eeee92296ea7b1abc3e76db75a Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 14:18:42 +0100 Subject: [PATCH 10/19] Changed the installation script for RethinkDB --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc770e1..1c03fcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ go: - 1.3.1 before_script: - - sudo add-apt-repository ppa:rethinkdb/ppa -y - - sudo apt-get update -q - - sudo apt-get install --force-yes rethinkdb + - source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list + - wget -qO- http://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add - + - sudo apt-get update + - sudo apt-get install rethinkdb - rethinkdb --bind all & From 6b65ea8a0633cca9d364a5d554232a04dded2aa8 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 22:08:17 +0100 Subject: [PATCH 11/19] Crapload of random usecase tests --- .../{behavioral_test.go => accounts_test.go} | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) rename routes/{behavioral_test.go => accounts_test.go} (67%) diff --git a/routes/behavioral_test.go b/routes/accounts_test.go similarity index 67% rename from routes/behavioral_test.go rename to routes/accounts_test.go index 102583a..daf67fc 100644 --- a/routes/behavioral_test.go +++ b/routes/accounts_test.go @@ -87,6 +87,25 @@ func TestHello(t *testing.T) { require.Equal(t, "Lavaboom API", helloResponse.Message) } +func TestAccountsCreateInvalid(t *testing.T) { + // POST /accounts - invalid + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: "!@#!@#", + }.Do() + require.Nil(t, err, "querying invalid /accounts should not return an error") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + env.Log.Print(response) + require.Nil(t, err, "unmarshaling invalid account creation should not return an error") + require.False(t, response.Success, "request should fail") + require.Equal(t, "Invalid input format", response.Message, "proper message should be returned") +} + func TestAccountsCreateUnknown(t *testing.T) { // POST /accounts - unknown result, err := goreq.Request{ @@ -169,6 +188,123 @@ func TestAccountsCreateInvited(t *testing.T) { require.Equal(t, "Invalid invitation token", response2.Message, "invalid message returned by invalid token acc creation") } +func TestAccountsCreateInvitedExisting(t *testing.T) { + const ( + username = "jeremy" + password = "potato" + ) + + // Prepare a token + inviteToken := models.Token{ + Resource: models.MakeResource("", "test invite token"), + Type: "invite", + } + inviteToken.ExpireSoon() + + err := env.Tokens.Insert(inviteToken) + require.Nil(t, err, "inserting a new invitation token should not return an error") + + // POST /accounts - invited + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, + }.Do() + require.Nil(t, err, "querying existing invited /accounts should not return an error") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling existing invited account creation should not return an error") + + // Check the result's contents + require.False(t, response.Success, "creating a new account using inv registration should fail") + require.Equal(t, "Username already exists", response.Message, "invalid message returned by existing invited acc creation") +} + +func TestAccountsCreateInvitedExpired(t *testing.T) { + const ( + username = "jeremy2" + password = "potato2" + ) + + // Prepare a token + inviteToken := models.Token{ + Resource: models.MakeResource("", "test invite token"), + Type: "invite", + } + inviteToken.ExpiryDate = time.Now().Truncate(time.Hour) + + err := env.Tokens.Insert(inviteToken) + require.Nil(t, err, "inserting a new invitation token should not return an error") + + // POST /accounts - invited + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, + }.Do() + require.Nil(t, err, "querying expired invited /accounts should not return an error") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling expired invited account creation should not return an error") + + // Check the result's contents + require.False(t, response.Success, "creating a new account using inv registration should fail") + require.Equal(t, "Expired invitation token", response.Message, "invalid message returned by expired invited acc creation") +} + +func TestAccountsCreateInvitedWrongType(t *testing.T) { + const ( + username = "jeremy2" + password = "potato2" + ) + + // Prepare a token + inviteToken := models.Token{ + Resource: models.MakeResource("", "test not invite token"), + Type: "not invite", + } + inviteToken.ExpiryDate = time.Now().Truncate(time.Hour) + + err := env.Tokens.Insert(inviteToken) + require.Nil(t, err, "inserting a new not invitation token should not return an error") + + // POST /accounts - invited + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, + }.Do() + require.Nil(t, err, "querying wrong type invited /accounts should not return an error") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling wrong type invited account creation should not return an error") + + // Check the result's contents + require.False(t, response.Success, "creating a new account using inv registration should fail") + require.Equal(t, "Invalid invitation token", response.Message, "invalid message returned by wrong type invited acc creation") +} + func TestAccountsCreateClassic(t *testing.T) { const ( username = "jeremy_was_invited" @@ -199,6 +335,28 @@ func TestAccountsCreateClassic(t *testing.T) { require.NotEmpty(t, createClassicResponse.Account.ID, "newly created account's id should not be empty") } +func TestAccountsCreateQueue(t *testing.T) { + // POST /accounts - queue + result, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + AltEmail: "something@example.com", + }, + }.Do() + require.Nil(t, err, "querying /accounts to queue") + + // Unmarshal the response + var response routes.AccountsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling queue response create should not fail") + + // Check the result's contents + require.False(t, response.Success, "creating a new account using queue registration failed") + require.Equal(t, "Sorry, not implemented yet", response.Message, "invalid message returned by queue acc creation") +} + func TestTokensCreate(t *testing.T) { // log in as mr jeremy potato const ( From 6eb734fa1123dadae4df24382534498cc1b111a0 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Wed, 26 Nov 2014 22:22:57 +0100 Subject: [PATCH 12/19] Removed some code from accounts to increase the coverage --- routes/accounts.go | 104 +++++----------------------------------- routes/accounts_test.go | 20 ++++++++ 2 files changed, 31 insertions(+), 93 deletions(-) diff --git a/routes/accounts.go b/routes/accounts.go index da077a3..cb775d7 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -21,7 +21,7 @@ type AccountsListResponse struct { func AccountsList(w http.ResponseWriter, r *http.Request) { utils.JSONResponse(w, 501, &AccountsListResponse{ Success: false, - Message: "Method not implemented", + Message: "Sorry, not implemented yet", }) } @@ -228,14 +228,7 @@ type AccountsGetResponse struct { // AccountsGet returns the information about the specified account func AccountsGet(c web.C, w http.ResponseWriter, r *http.Request) { // Get the account ID from the request - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 409, &AccountsGetResponse{ - Success: false, - Message: "Invalid user ID", - }) - return - } + id := c.URLParams["id"] // Right now we only support "me" as the ID if id != "me" { @@ -252,27 +245,9 @@ func AccountsGet(c web.C, w http.ResponseWriter, r *http.Request) { // Fetch the user object from the database user, err := env.Accounts.GetAccount(session.Owner) if err != nil { - // The session refers to a non-existing user - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Warn("Valid session referred to a removed account") - - // Try to remove the orphaned session - if err := env.Tokens.DeleteID(session.ID); err != nil { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Error("Unable to remove an orphaned session") - } else { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - }).Info("Removed an orphaned session") - } - - utils.JSONResponse(w, 410, &AccountsGetResponse{ + utils.JSONResponse(w, 500, &AccountsDeleteResponse{ Success: false, - Message: "Account disabled", + Message: "Unable to resolve the account", }) return } @@ -316,14 +291,7 @@ func AccountsUpdate(c web.C, w http.ResponseWriter, r *http.Request) { } // Get the account ID from the request - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 409, &AccountsUpdateResponse{ - Success: false, - Message: "Invalid user ID", - }) - return - } + id := c.URLParams["id"] // Right now we only support "me" as the ID if id != "me" { @@ -340,27 +308,9 @@ func AccountsUpdate(c web.C, w http.ResponseWriter, r *http.Request) { // Fetch the user object from the database user, err := env.Accounts.GetAccount(session.Owner) if err != nil { - // The session refers to a non-existing user - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Warn("Valid session referred to a removed account") - - // Try to remove the orphaned session - if err := env.Tokens.DeleteID(session.ID); err != nil { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Error("Unable to remove an orphaned session") - } else { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - }).Info("Removed an orphaned session") - } - - utils.JSONResponse(w, 410, &AccountsUpdateResponse{ + utils.JSONResponse(w, 500, &AccountsDeleteResponse{ Success: false, - Message: "Account disabled", + Message: "Unable to resolve the account", }) return } @@ -421,14 +371,7 @@ type AccountsDeleteResponse struct { // AccountsDelete deletes an account and everything related to it. func AccountsDelete(c web.C, w http.ResponseWriter, r *http.Request) { // Get the account ID from the request - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 409, &AccountsDeleteResponse{ - Success: false, - Message: "Invalid user ID", - }) - return - } + id := c.URLParams["id"] // Right now we only support "me" as the ID if id != "me" { @@ -445,27 +388,9 @@ func AccountsDelete(c web.C, w http.ResponseWriter, r *http.Request) { // Fetch the user object from the database user, err := env.Accounts.GetAccount(session.Owner) if err != nil { - // The session refers to a non-existing user - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Warn("Valid session referred to a removed account") - - // Try to remove the orphaned session - if err := env.Tokens.DeleteID(session.ID); err != nil { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - "error": err, - }).Error("Unable to remove an orphaned session") - } else { - env.Log.WithFields(logrus.Fields{ - "id": session.ID, - }).Info("Removed an orphaned session") - } - - utils.JSONResponse(w, 410, &AccountsDeleteResponse{ + utils.JSONResponse(w, 500, &AccountsDeleteResponse{ Success: false, - Message: "Account disabled", + Message: "Unable to resolve the account", }) return } @@ -522,14 +447,7 @@ type AccountsWipeDataResponse struct { // AccountsWipeData wipes all data except the actual account and billing info. func AccountsWipeData(c web.C, w http.ResponseWriter, r *http.Request) { // Get the account ID from the request - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 409, &AccountsWipeDataResponse{ - Success: false, - Message: "Invalid user ID", - }) - return - } + id := c.URLParams["id"] // Right now we only support "me" as the ID if id != "me" { diff --git a/routes/accounts_test.go b/routes/accounts_test.go index daf67fc..1853394 100644 --- a/routes/accounts_test.go +++ b/routes/accounts_test.go @@ -390,6 +390,26 @@ func TestTokensCreate(t *testing.T) { authToken = response.Token.ID } +func TestAccountsList(t *testing.T) { + // GET /accounts + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "querying /accounts should not fail") + + // Unmarshal the response + var response routes.AccountsListResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling queue response create should not fail") + + // Check the result's contents + require.False(t, response.Success, "creating a new account using queue registration failed") + require.Equal(t, "Sorry, not implemented yet", response.Message, "invalid message returned by queue acc creation") +} + func TestAccountsGetMe(t *testing.T) { // GET /accounts/me request := goreq.Request{ From 51f52fc0a9763b8d6bdb0d32c9117878478cb4bc Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Thu, 27 Nov 2014 13:36:43 +0100 Subject: [PATCH 13/19] Added last tests to the accounts suite --- routes/accounts_test.go | 179 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 3 deletions(-) diff --git a/routes/accounts_test.go b/routes/accounts_test.go index 1853394..2c65f15 100644 --- a/routes/accounts_test.go +++ b/routes/accounts_test.go @@ -335,6 +335,39 @@ func TestAccountsCreateClassic(t *testing.T) { require.NotEmpty(t, createClassicResponse.Account.ID, "newly created account's id should not be empty") } +func TestAccountsCreateClassicDisabled(t *testing.T) { + const ( + username = "jeremy_was_invited" + password = "potato" + ) + + env.Config.ClassicRegistration = false + + // POST /accounts - classic + createClassicResult, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username + "classic", + Password: password, + AltEmail: "something@example.com", + }, + }.Do() + require.Nil(t, err, "querying invited /accounts should not return an error") + + // Unmarshal the response + var createClassicResponse routes.AccountsCreateResponse + err = createClassicResult.Body.FromJsonTo(&createClassicResponse) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.False(t, createClassicResponse.Success, "creating a new account using classic registration failed") + require.Equal(t, "Classic registration is disabled", createClassicResponse.Message, "invalid message returned by invited acc creation") + + env.Config.ClassicRegistration = true +} + func TestAccountsCreateQueue(t *testing.T) { // POST /accounts - queue result, err := goreq.Request{ @@ -430,6 +463,25 @@ func TestAccountsGetMe(t *testing.T) { require.Equal(t, "jeremy", response.Account.Name, "username should be the previously registered one") } +func TestAccountsGetNotMe(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/not-me", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "querying /accounts/not-me should not return an error") + + // Unmarshal the response + var response routes.AccountsGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling /accounts/not-me should not return an error") + + // Check the result's contents + require.False(t, response.Success, "getting /accounts/not-me should fail") + require.Equal(t, `Only the "me" user is implemented`, response.Message, "/accounts/not-me should return a proper message") +} + func TestAccountUpdateMe(t *testing.T) { // PUT /accounts/me request := goreq.Request{ @@ -456,9 +508,100 @@ func TestAccountUpdateMe(t *testing.T) { require.True(t, response.Success, "updating /accounts/me should succeed") require.Equal(t, "jeremy", response.Account.Name, "username should not be changed") require.Equal(t, "john.cabbage@example.com", response.Account.AltEmail, "alt email should be changed") - //valid, _, err := response.Account.VerifyPassword("cabbage") - //require.Nil(t, err, "verifying the password should not return an error") - //require.True(t, valid, "password should be changed") +} + +func TestAccountUpdateInvalid(t *testing.T) { + // PUT /accounts/me + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/accounts/me", + ContentType: "application/json", + Body: "123123123!@#!@#!@#", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "updating account should not return an error") + + // Unmarshal the response + var response routes.AccountsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account update response should not return an error") + + // Check the result's contents + require.Equal(t, "Invalid input format", response.Message, "response message should be valid") + require.False(t, response.Success, "updating invalid /accounts/me should fail") +} + +func TestAccountUpdateNotMe(t *testing.T) { + // PUT /accounts/me + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/accounts/not-me", + ContentType: "application/json", + Body: &routes.AccountsUpdateRequest{ + CurrentPassword: "potato", + NewPassword: "cabbage", + AltEmail: "john.cabbage@example.com", + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "updating account should not return an error") + + // Unmarshal the response + var response routes.AccountsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account update response should not return an error") + + // Check the result's contents + require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") + require.False(t, response.Success, "updating /accounts/not-me should fail") +} + +func TestAccountUpdateMeInvalidPassword(t *testing.T) { + // PUT /accounts/me + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/accounts/me", + ContentType: "application/json", + Body: &routes.AccountsUpdateRequest{ + CurrentPassword: "potato2", + NewPassword: "cabbage", + AltEmail: "john.cabbage@example.com", + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "updating account should not return an error") + + // Unmarshal the response + var response routes.AccountsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account update response should not return an error") + + // Check the result's contents + require.Equal(t, "Invalid current password", response.Message, "response message should be valid") + require.False(t, response.Success, "updating /accounts/me should fail") +} + +func TestAccountsWipeDataNotMe(t *testing.T) { + // POST /accounts/me/wipe-data + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts/not-me/wipe-data", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "wiping account should not return an error") + + // Unmarshal the response + var response routes.AccountsWipeDataResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account wipe response should not return an error") + + // Check the result's contents + require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") + require.False(t, response.Success, "triggering /accounts/wipe-data should fail") } func TestAccountsWipeData(t *testing.T) { @@ -481,6 +624,36 @@ func TestAccountsWipeData(t *testing.T) { require.True(t, response.Success, "triggering /accounts/wipe-data should succeed") } +func TestAccountsDeleteNotMe(t *testing.T) { + // Prepare a token + token := models.Token{ + Resource: models.MakeResource(accountID, "test invite token"), + Type: "auth", + } + token.ExpireSoon() + + err := env.Tokens.Insert(token) + require.Nil(t, err, "inserting a new auth toekn token should not return an error") + + // DELETE /accounts/me + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/accounts/not-me", + } + request.AddHeader("Authorization", "Bearer "+token.ID) + result, err := request.Do() + require.Nil(t, err, "deleting account should not return an error") + + // Unmarshal the response + var response routes.AccountsWipeDataResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling account delete response should not return an error") + + // Check the result's contents + require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") + require.False(t, response.Success, "triggering delete /account/me should fail") +} + func TestAccountsDelete(t *testing.T) { // Prepare a token token := models.Token{ From 5340c8c1a6f18e8d902201570f4def69b7a1e19a Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Fri, 28 Nov 2014 13:45:26 +0100 Subject: [PATCH 14/19] Get token test --- routes/accounts_test.go | 77 +---------------------------- routes/hello_test.go | 25 ++++++++++ routes/init_test.go | 68 ++++++++++++++++++++++++++ routes/tokens_test.go | 105 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+), 76 deletions(-) create mode 100644 routes/hello_test.go create mode 100644 routes/init_test.go create mode 100644 routes/tokens_test.go diff --git a/routes/accounts_test.go b/routes/accounts_test.go index 2c65f15..df78c66 100644 --- a/routes/accounts_test.go +++ b/routes/accounts_test.go @@ -1,92 +1,17 @@ package routes_test import ( - "net/http/httptest" "testing" "time" - "github.com/dancannon/gorethink" "github.com/franela/goreq" "github.com/stretchr/testify/require" "github.com/lavab/api/env" "github.com/lavab/api/models" "github.com/lavab/api/routes" - "github.com/lavab/api/setup" ) -var ( - server *httptest.Server - accountID string - authToken string -) - -func init() { - // Mock data - env.Config = &env.Flags{ - APIVersion: "v0", - LogFormatterType: "text", - ForceColors: true, - - SessionDuration: 72, - ClassicRegistration: true, - - RethinkDBURL: "127.0.0.1:28015", - RethinkDBKey: "", - RethinkDBDatabase: "test", - } - - // Connect to the RethinkDB server - rdbSession, err := gorethink.Connect(gorethink.ConnectOpts{ - Address: env.Config.RethinkDBURL, - AuthKey: env.Config.RethinkDBKey, - MaxIdle: 10, - IdleTimeout: time.Second * 10, - }) - if err != nil { - panic("connecting to RethinkDB should not return an error, got " + err.Error()) - } - - // Clear the test database - err = gorethink.DbDrop("test").Exec(rdbSession) - if err != nil { - panic("removing the test database should not return an error, got " + err.Error()) - } - - // Disconnect - err = rdbSession.Close() - if err != nil { - panic("closing the RethinkDB session should not return an error, got " + err.Error()) - } - - // Prepare a new mux (initialize the API) - mux := setup.PrepareMux(env.Config) - if mux == nil { - panic("returned mux was nil") - } - - // Set up a new temporary HTTP test server - server = httptest.NewServer(mux) - if server == nil { - panic("returned httptest server was nil") - } -} - -func TestHello(t *testing.T) { - // Request the / route - helloResult, err := goreq.Request{ - Method: "GET", - Uri: server.URL, - }.Do() - require.Nil(t, err, "requesting / should not return an error") - - // Unmarshal the response - var helloResponse routes.HelloResponse - err = helloResult.Body.FromJsonTo(&helloResponse) - require.Nil(t, err, "unmarshaling / result should not return an error") - require.Equal(t, "Lavaboom API", helloResponse.Message) -} - func TestAccountsCreateInvalid(t *testing.T) { // POST /accounts - invalid result, err := goreq.Request{ @@ -390,7 +315,7 @@ func TestAccountsCreateQueue(t *testing.T) { require.Equal(t, "Sorry, not implemented yet", response.Message, "invalid message returned by queue acc creation") } -func TestTokensCreate(t *testing.T) { +func TestAccountsPrepareToken(t *testing.T) { // log in as mr jeremy potato const ( username = "jeremy" diff --git a/routes/hello_test.go b/routes/hello_test.go new file mode 100644 index 0000000..061dc81 --- /dev/null +++ b/routes/hello_test.go @@ -0,0 +1,25 @@ +package routes_test + +import ( + "testing" + + "github.com/franela/goreq" + "github.com/stretchr/testify/require" + + "github.com/lavab/api/routes" +) + +func TestHello(t *testing.T) { + // Request the / route + helloResult, err := goreq.Request{ + Method: "GET", + Uri: server.URL, + }.Do() + require.Nil(t, err, "requesting / should not return an error") + + // Unmarshal the response + var helloResponse routes.HelloResponse + err = helloResult.Body.FromJsonTo(&helloResponse) + require.Nil(t, err, "unmarshaling / result should not return an error") + require.Equal(t, "Lavaboom API", helloResponse.Message) +} diff --git a/routes/init_test.go b/routes/init_test.go new file mode 100644 index 0000000..3c1ffb4 --- /dev/null +++ b/routes/init_test.go @@ -0,0 +1,68 @@ +package routes_test + +import ( + "net/http/httptest" + "time" + + "github.com/dancannon/gorethink" + + "github.com/lavab/api/env" + "github.com/lavab/api/setup" +) + +var ( + server *httptest.Server + accountID string + authToken string +) + +func init() { + // Mock data + env.Config = &env.Flags{ + APIVersion: "v0", + LogFormatterType: "text", + ForceColors: true, + + SessionDuration: 72, + ClassicRegistration: true, + + RethinkDBURL: "127.0.0.1:28015", + RethinkDBKey: "", + RethinkDBDatabase: "test", + } + + // Connect to the RethinkDB server + rdbSession, err := gorethink.Connect(gorethink.ConnectOpts{ + Address: env.Config.RethinkDBURL, + AuthKey: env.Config.RethinkDBKey, + MaxIdle: 10, + IdleTimeout: time.Second * 10, + }) + if err != nil { + panic("connecting to RethinkDB should not return an error, got " + err.Error()) + } + + // Clear the test database + err = gorethink.DbDrop("test").Exec(rdbSession) + if err != nil { + panic("removing the test database should not return an error, got " + err.Error()) + } + + // Disconnect + err = rdbSession.Close() + if err != nil { + panic("closing the RethinkDB session should not return an error, got " + err.Error()) + } + + // Prepare a new mux (initialize the API) + mux := setup.PrepareMux(env.Config) + if mux == nil { + panic("returned mux was nil") + } + + // Set up a new temporary HTTP test server + server = httptest.NewServer(mux) + if server == nil { + panic("returned httptest server was nil") + } +} diff --git a/routes/tokens_test.go b/routes/tokens_test.go new file mode 100644 index 0000000..e9abbcf --- /dev/null +++ b/routes/tokens_test.go @@ -0,0 +1,105 @@ +package routes_test + +import ( + "testing" + "time" + + "github.com/franela/goreq" + "github.com/stretchr/testify/require" + + "github.com/lavab/api/env" + "github.com/lavab/api/models" + "github.com/lavab/api/routes" +) + +func TestTokensPrepareAccount(t *testing.T) { + const ( + username = "jeremy" + password = "potato" + ) + + // Prepare a token + inviteToken := models.Token{ + Resource: models.MakeResource("", "test invite token"), + Type: "invite", + } + inviteToken.ExpireSoon() + + err := env.Tokens.Insert(inviteToken) + require.Nil(t, err, "inserting a new invitation token should not return an error") + + // POST /accounts - invited + result1, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, + }.Do() + require.Nil(t, err, "querying invited /accounts should not return an error") + + // Unmarshal the response + var response1 routes.AccountsCreateResponse + err = result1.Body.FromJsonTo(&response1) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.True(t, response1.Success, "creating a new account using inv registration failed") + require.Equal(t, "A new account was successfully created", response1.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, response1.Account.ID, "newly created account's id should not be empty") + + accountID = response1.Account.ID +} + +func TestTokensCreate(t *testing.T) { + // log in as mr jeremy potato + const ( + username = "jeremy" + password = "potato" + ) + // POST /accounts - classic + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Username: username, + Password: password, + Type: "auth", + }, + }.Do() + require.Nil(t, err, "querying existing /tokens should not return an error") + + // Unmarshal the response + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.True(t, response.Success, "creating a new token using existing account failed") + require.Equal(t, "Authentication successful", response.Message, "invalid message returned by invited acc creation") + require.NotEmpty(t, response.Token.ID, "newly created token's id should not be empty") + + // Populate the global token variable + authToken = response.Token.ID +} + +func TestTokensGet(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/tokens", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err, "qurying /tokens should not return an error") + + var response routes.TokensGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling should not return an error") + + require.True(t, response.Success, "request should be successful") + require.True(t, response.Expires.After(time.Now().UTC()), "expiry time has to be valid") +} From d97e6736e478e736e16762ae86b8df0d3eb994ae Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 29 Nov 2014 12:38:58 +0100 Subject: [PATCH 15/19] Tokens tests #2 --- routes/tokens_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/routes/tokens_test.go b/routes/tokens_test.go index e9abbcf..68e5463 100644 --- a/routes/tokens_test.go +++ b/routes/tokens_test.go @@ -87,6 +87,25 @@ func TestTokensCreate(t *testing.T) { authToken = response.Token.ID } +func TestTokensCreateInvalid(t *testing.T) { + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: "123123123###434$#$", + }.Do() + require.Nil(t, err, "querying existing /tokens should not return an error") + + // Unmarshal the response + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.False(t, response.Success) + require.Equal(t, "Invalid input format", response.Message) +} + func TestTokensGet(t *testing.T) { request := goreq.Request{ Method: "GET", From d97a4b9666b5bc192b1c87b6fdbdaa06ef6da02c Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 29 Nov 2014 19:07:31 +0100 Subject: [PATCH 16/19] Token tests --- routes/keys.go | 448 +++++++++++++++++++++--------------------- routes/tokens.go | 8 +- routes/tokens_test.go | 171 ++++++++++++++-- 3 files changed, 383 insertions(+), 244 deletions(-) diff --git a/routes/keys.go b/routes/keys.go index cbd4fce..a6ea771 100644 --- a/routes/keys.go +++ b/routes/keys.go @@ -1,224 +1,224 @@ -package routes - -import ( - "encoding/hex" - "fmt" - "net/http" - "strings" - - "github.com/Sirupsen/logrus" - "github.com/zenazn/goji/web" - "golang.org/x/crypto/openpgp" - - "github.com/lavab/api/env" - "github.com/lavab/api/models" - "github.com/lavab/api/utils" -) - -// KeysListResponse contains the result of the KeysList request -type KeysListResponse struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Keys *[]string `json:"keys,omitempty"` -} - -// KeysList responds with the list of keys assigned to the spiecified email -func KeysList(w http.ResponseWriter, r *http.Request) { - // Get the username from the GET query - user := r.URL.Query().Get("user") - if user == "" { - utils.JSONResponse(w, 409, &KeysListResponse{ - Success: false, - Message: "Invalid username", - }) - return - } - - // Find all keys owner by user - keys, err := env.Keys.FindByName(user) - if err != nil { - utils.JSONResponse(w, 500, &KeysListResponse{ - Success: false, - Message: "Internal server error (KE/LI/01)", - }) - return - } - - // Equivalent of _.keys(keys) in JavaScript with underscore.js - keyIDs := []string{} - for _, key := range keys { - keyIDs = append(keyIDs, key.ID) - } - - // Respond with list of keys - utils.JSONResponse(w, 200, &KeysListResponse{ - Success: true, - Keys: &keyIDs, - }) -} - -// KeysCreateRequest contains the data passed to the KeysCreate endpoint. -type KeysCreateRequest struct { - Key string `json:"key" schema:"key"` // gpg armored key - Image string `json:"image" schema:"image"` // todo -} - -// KeysCreateResponse contains the result of the KeysCreate request. -type KeysCreateResponse struct { - Success bool `json:"success"` - Message string `json:"message"` - Key *models.Key `json:"key,omitempty"` -} - -// KeysCreate appens a new key to the server -func KeysCreate(c web.C, w http.ResponseWriter, r *http.Request) { - // Decode the request - var input KeysCreateRequest - err := utils.ParseRequest(r, &input) - if err != nil { - env.Log.WithFields(logrus.Fields{ - "error": err, - }).Warn("Unable to decode a request") - - utils.JSONResponse(w, 409, &KeysCreateResponse{ - Success: false, - Message: "Invalid input format", - }) - return - } - - // Get the session - session := c.Env["token"].(*models.Token) - - // Parse the armored key - entityList, err := openpgp.ReadArmoredKeyRing(strings.NewReader(input.Key)) - if err != nil { - utils.JSONResponse(w, 409, &KeysCreateResponse{ - Success: false, - Message: "Invalid key format", - }) - - env.Log.WithFields(logrus.Fields{ - "error": err, - "list": entityList, - }).Warn("Cannot parse an armored key") - return - } - - // Get the account from db - account, err := env.Accounts.GetAccount(session.Owner) - if err != nil { - utils.JSONResponse(w, 500, &KeysCreateResponse{ - Success: false, - Message: "Internal server error - KE/CR/01", - }) - - env.Log.WithFields(logrus.Fields{ - "error": err, - "id": session.Owner, - }).Error("Cannot fetch user from database") - return - } - - // Let's hope that the user is capable of sending proper armored keys - publicKey := entityList[0] - - // Encode the fingerprint - id := hex.EncodeToString(publicKey.PrimaryKey.Fingerprint[:]) - - // Get the key's bit length - should not return an error - bitLength, _ := publicKey.PrimaryKey.BitLength() - - // Allocate a new key - key := &models.Key{ - Resource: models.MakeResource( - session.Owner, - fmt.Sprintf( - "%d/%s public key", - bitLength, - publicKey.PrimaryKey.KeyIdString(), - ), - ), - OwnerName: account.Name, - Key: input.Key, - KeyID: publicKey.PrimaryKey.KeyIdString(), - KeyIDShort: publicKey.PrimaryKey.KeyIdShortString(), - } - - // Update id as we can't do it directly during allocation - key.ID = id - - // Try to insert it into the database - if err := env.Keys.Insert(key); err != nil { - utils.JSONResponse(w, 500, &KeysCreateResponse{ - Success: false, - Message: "Internal server error - KE/CR/02", - }) - - env.Log.WithFields(logrus.Fields{ - "error": err, - }).Error("Could not insert a key to the database") - return - } - - // Return the inserted key - utils.JSONResponse(w, 201, &KeysCreateResponse{ - Success: true, - Message: "A new key has been successfully inserted", - Key: key, - }) -} - -// KeysGetResponse contains the result of the KeysGet request. -type KeysGetResponse struct { - Success bool `json:"success"` - Message string `json:"message,omitempty"` - Key *models.Key `json:"key,omitempty"` -} - -// KeysGet does *something* - TODO -func KeysGet(c web.C, w http.ResponseWriter, r *http.Request) { - // Get ID from the passed URL params - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 404, &KeysGetResponse{ - Success: false, - Message: "Requested key does not exist on our server", - }) - return - } - - // Fetch the requested key from the database - key, err := env.Keys.FindByFingerprint(id) - if err != nil { - env.Log.WithFields(logrus.Fields{ - "error": err, - }).Warn("Unable to fetch the requested key from the database") - - utils.JSONResponse(w, 404, &KeysGetResponse{ - Success: false, - Message: "Requested key does not exist on our server", - }) - return - } - - // Return the requested key - utils.JSONResponse(w, 200, &KeysGetResponse{ - Success: true, - Key: key, - }) -} - -// KeysVoteResponse contains the result of the KeysVote request. -type KeysVoteResponse struct { - Success bool `json:"success"` - Message string `json:"message"` -} - -// KeysVote does *something* - TODO -func KeysVote(w http.ResponseWriter, r *http.Request) { - utils.JSONResponse(w, 501, &KeysVoteResponse{ - Success: false, - Message: "Sorry, not implemented yet", - }) -} +package routes + +import ( + "encoding/hex" + "fmt" + "net/http" + "strings" + + "github.com/Sirupsen/logrus" + "github.com/zenazn/goji/web" + "golang.org/x/crypto/openpgp" + + "github.com/lavab/api/env" + "github.com/lavab/api/models" + "github.com/lavab/api/utils" +) + +// KeysListResponse contains the result of the KeysList request +type KeysListResponse struct { + Success bool `json:"success"` + Message string `json:"message,omitempty"` + Keys *[]string `json:"keys,omitempty"` +} + +// KeysList responds with the list of keys assigned to the spiecified email +func KeysList(w http.ResponseWriter, r *http.Request) { + // Get the username from the GET query + user := r.URL.Query().Get("user") + if user == "" { + utils.JSONResponse(w, 409, &KeysListResponse{ + Success: false, + Message: "Invalid username", + }) + return + } + + // Find all keys owner by user + keys, err := env.Keys.FindByName(user) + if err != nil { + utils.JSONResponse(w, 500, &KeysListResponse{ + Success: false, + Message: "Internal server error (KE/LI/01)", + }) + return + } + + // Equivalent of _.keys(keys) in JavaScript with underscore.js + keyIDs := []string{} + for _, key := range keys { + keyIDs = append(keyIDs, key.ID) + } + + // Respond with list of keys + utils.JSONResponse(w, 200, &KeysListResponse{ + Success: true, + Keys: &keyIDs, + }) +} + +// KeysCreateRequest contains the data passed to the KeysCreate endpoint. +type KeysCreateRequest struct { + Key string `json:"key" schema:"key"` // gpg armored key + Image string `json:"image" schema:"image"` // todo +} + +// KeysCreateResponse contains the result of the KeysCreate request. +type KeysCreateResponse struct { + Success bool `json:"success"` + Message string `json:"message"` + Key *models.Key `json:"key,omitempty"` +} + +// KeysCreate appens a new key to the server +func KeysCreate(c web.C, w http.ResponseWriter, r *http.Request) { + // Decode the request + var input KeysCreateRequest + err := utils.ParseRequest(r, &input) + if err != nil { + env.Log.WithFields(logrus.Fields{ + "error": err, + }).Warn("Unable to decode a request") + + utils.JSONResponse(w, 409, &KeysCreateResponse{ + Success: false, + Message: "Invalid input format", + }) + return + } + + // Get the session + session := c.Env["token"].(*models.Token) + + // Parse the armored key + entityList, err := openpgp.ReadArmoredKeyRing(strings.NewReader(input.Key)) + if err != nil { + utils.JSONResponse(w, 409, &KeysCreateResponse{ + Success: false, + Message: "Invalid key format", + }) + + env.Log.WithFields(logrus.Fields{ + "error": err, + "list": entityList, + }).Warn("Cannot parse an armored key") + return + } + + // Get the account from db + account, err := env.Accounts.GetAccount(session.Owner) + if err != nil { + utils.JSONResponse(w, 500, &KeysCreateResponse{ + Success: false, + Message: "Internal server error - KE/CR/01", + }) + + env.Log.WithFields(logrus.Fields{ + "error": err, + "id": session.Owner, + }).Error("Cannot fetch user from database") + return + } + + // Let's hope that the user is capable of sending proper armored keys + publicKey := entityList[0] + + // Encode the fingerprint + id := hex.EncodeToString(publicKey.PrimaryKey.Fingerprint[:]) + + // Get the key's bit length - should not return an error + bitLength, _ := publicKey.PrimaryKey.BitLength() + + // Allocate a new key + key := &models.Key{ + Resource: models.MakeResource( + session.Owner, + fmt.Sprintf( + "%d/%s public key", + bitLength, + publicKey.PrimaryKey.KeyIdString(), + ), + ), + OwnerName: account.Name, + Key: input.Key, + KeyID: publicKey.PrimaryKey.KeyIdString(), + KeyIDShort: publicKey.PrimaryKey.KeyIdShortString(), + } + + // Update id as we can't do it directly during allocation + key.ID = id + + // Try to insert it into the database + if err := env.Keys.Insert(key); err != nil { + utils.JSONResponse(w, 500, &KeysCreateResponse{ + Success: false, + Message: "Internal server error - KE/CR/02", + }) + + env.Log.WithFields(logrus.Fields{ + "error": err, + }).Error("Could not insert a key to the database") + return + } + + // Return the inserted key + utils.JSONResponse(w, 201, &KeysCreateResponse{ + Success: true, + Message: "A new key has been successfully inserted", + Key: key, + }) +} + +// KeysGetResponse contains the result of the KeysGet request. +type KeysGetResponse struct { + Success bool `json:"success"` + Message string `json:"message,omitempty"` + Key *models.Key `json:"key,omitempty"` +} + +// KeysGet does *something* - TODO +func KeysGet(c web.C, w http.ResponseWriter, r *http.Request) { + // Get ID from the passed URL params + id, ok := c.URLParams["id"] + if !ok { + utils.JSONResponse(w, 404, &KeysGetResponse{ + Success: false, + Message: "Requested key does not exist on our server", + }) + return + } + + // Fetch the requested key from the database + key, err := env.Keys.FindByFingerprint(id) + if err != nil { + env.Log.WithFields(logrus.Fields{ + "error": err, + }).Warn("Unable to fetch the requested key from the database") + + utils.JSONResponse(w, 404, &KeysGetResponse{ + Success: false, + Message: "Requested key does not exist on our server", + }) + return + } + + // Return the requested key + utils.JSONResponse(w, 200, &KeysGetResponse{ + Success: true, + Key: key, + }) +} + +// KeysVoteResponse contains the result of the KeysVote request. +type KeysVoteResponse struct { + Success bool `json:"success"` + Message string `json:"message"` +} + +// KeysVote does *something* - TODO +func KeysVote(w http.ResponseWriter, r *http.Request) { + utils.JSONResponse(w, 501, &KeysVoteResponse{ + Success: false, + Message: "Sorry, not implemented yet", + }) +} diff --git a/routes/tokens.go b/routes/tokens.go index 54e4ca2..3b11567 100644 --- a/routes/tokens.go +++ b/routes/tokens.go @@ -151,9 +151,9 @@ func TokensDelete(c web.C, w http.ResponseWriter, r *http.Request) { "id": id, }).Warn("Unable to find the token") - utils.JSONResponse(w, 500, &TokensDeleteResponse{ - Success: true, - Message: "Internal server error - TO/DE/01", + utils.JSONResponse(w, 404, &TokensDeleteResponse{ + Success: false, + Message: "Invalid token ID", }) return } @@ -166,7 +166,7 @@ func TokensDelete(c web.C, w http.ResponseWriter, r *http.Request) { }).Error("Unable to delete a token") utils.JSONResponse(w, 500, &TokensDeleteResponse{ - Success: true, + Success: false, Message: "Internal server error - TO/DE/02", }) return diff --git a/routes/tokens_test.go b/routes/tokens_test.go index 68e5463..87755da 100644 --- a/routes/tokens_test.go +++ b/routes/tokens_test.go @@ -87,23 +87,84 @@ func TestTokensCreate(t *testing.T) { authToken = response.Token.ID } +func TestTokensCreateNonAuth(t *testing.T) { + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Type: "not-auth", + }, + }.Do() + require.Nil(t, err) + + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Only auth tokens are implemented", response.Message) +} + +func TestTokensCreateWrongUsername(t *testing.T) { + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Type: "auth", + Username: "not-jeremy", + Password: "potato", + }, + }.Do() + require.Nil(t, err) + + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Wrong username or password", response.Message) +} + +func TestTokensCreateWrongPassword(t *testing.T) { + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Type: "auth", + Username: "jeremy", + Password: "not-potato", + }, + }.Do() + require.Nil(t, err) + + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Wrong username or password", response.Message) +} + func TestTokensCreateInvalid(t *testing.T) { - request, err := goreq.Request{ - Method: "POST", - Uri: server.URL + "/tokens", - ContentType: "application/json", - Body: "123123123###434$#$", - }.Do() - require.Nil(t, err, "querying existing /tokens should not return an error") - - // Unmarshal the response - var response routes.TokensCreateResponse - err = request.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") - - // Check the result's contents - require.False(t, response.Success) - require.Equal(t, "Invalid input format", response.Message) + request, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: "123123123###434$#$", + }.Do() + require.Nil(t, err, "querying existing /tokens should not return an error") + + // Unmarshal the response + var response routes.TokensCreateResponse + err = request.Body.FromJsonTo(&response) + require.Nil(t, err, "unmarshaling invited account creation should not return an error") + + // Check the result's contents + require.False(t, response.Success) + require.Equal(t, "Invalid input format", response.Message) } func TestTokensGet(t *testing.T) { @@ -122,3 +183,81 @@ func TestTokensGet(t *testing.T) { require.True(t, response.Success, "request should be successful") require.True(t, response.Expires.After(time.Now().UTC()), "expiry time has to be valid") } + +func TestTokensDeleteById(t *testing.T) { + const ( + username = "jeremy" + password = "potato" + ) + + request1, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Username: username, + Password: password, + Type: "auth", + }, + }.Do() + require.Nil(t, err) + + // Unmarshal the response + var response1 routes.TokensCreateResponse + err = request1.Body.FromJsonTo(&response1) + require.Nil(t, err) + + // Check the result's contents + require.True(t, response1.Success) + require.Equal(t, "Authentication successful", response1.Message) + require.NotEmpty(t, response1.Token.ID) + + request2 := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/tokens/" + response1.Token.ID, + } + request2.AddHeader("Authorization", "Bearer "+authToken) + result2, err := request2.Do() + require.Nil(t, err) + + var response2 routes.TokensDeleteResponse + err = result2.Body.FromJsonTo(&response2) + require.Nil(t, err) + + require.True(t, response2.Success) + require.Equal(t, "Successfully logged out", response2.Message) +} + +func TestTokensDeleteByInvalidID(t *testing.T) { + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/tokens/123", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.TokensDeleteResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Invalid token ID", response.Message) +} + +func TestTokensDeleteCurrent(t *testing.T) { + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/tokens", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.TokensDeleteResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.Equal(t, "Successfully logged out", response.Message) +} From d08ab7d79a874f4c70c2ab2921b4fac88642e79c Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 29 Nov 2014 19:48:20 +0100 Subject: [PATCH 17/19] Contacts create and list --- routes/contacts.go | 16 ++-- routes/contacts_test.go | 159 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 8 deletions(-) create mode 100644 routes/contacts_test.go diff --git a/routes/contacts.go b/routes/contacts.go index 5d8e18a..0e46ef4 100644 --- a/routes/contacts.go +++ b/routes/contacts.go @@ -30,7 +30,7 @@ func ContactsList(c web.C, w http.ResponseWriter, r *http.Request) { "error": err, }).Error("Unable to fetch contacts") - utils.JSONResponse(w, 500, &AccountsDeleteResponse{ + utils.JSONResponse(w, 500, &ContactsListResponse{ Success: false, Message: "Internal error (code CO/LI/01)", }) @@ -38,7 +38,7 @@ func ContactsList(c web.C, w http.ResponseWriter, r *http.Request) { } utils.JSONResponse(w, 501, &ContactsListResponse{ - Success: false, + Success: true, Contacts: &contacts, }) } @@ -48,8 +48,8 @@ type ContactsCreateRequest struct { Data string `json:"data" schema:"data"` Name string `json:"name" schema:"name"` Encoding string `json:"encoding" schema:"encoding"` - VersionMajor *int `json:"version_major" schema:"version_major"` - VersionMinor *int `json:"version_minor" schema:"version_minor"` + VersionMajor int `json:"version_major" schema:"version_major"` + VersionMinor int `json:"version_minor" schema:"version_minor"` } // ContactsCreateResponse contains the result of the ContactsCreate request. @@ -80,7 +80,7 @@ func ContactsCreate(c web.C, w http.ResponseWriter, r *http.Request) { session := c.Env["token"].(*models.Token) // Ensure that the input data isn't empty - if input.Data != "" || input.Name != "" || input.Encoding != "" || input.VersionMajor != nil || input.VersionMinor != nil { + if input.Data == "" || input.Name == "" || input.Encoding == "" { utils.JSONResponse(w, 400, &ContactsCreateResponse{ Success: false, Message: "Invalid request", @@ -94,8 +94,8 @@ func ContactsCreate(c web.C, w http.ResponseWriter, r *http.Request) { Encoding: input.Encoding, Data: input.Data, Schema: "contact", - VersionMajor: *input.VersionMajor, - VersionMinor: *input.VersionMinor, + VersionMajor: input.VersionMajor, + VersionMinor: input.VersionMinor, }, Resource: models.MakeResource(session.Owner, input.Name), } @@ -115,7 +115,7 @@ func ContactsCreate(c web.C, w http.ResponseWriter, r *http.Request) { utils.JSONResponse(w, 201, &ContactsCreateResponse{ Success: true, - Message: "A new account was successfully created", + Message: "A new contact was successfully created", Contact: contact, }) } diff --git a/routes/contacts_test.go b/routes/contacts_test.go new file mode 100644 index 0000000..40f353f --- /dev/null +++ b/routes/contacts_test.go @@ -0,0 +1,159 @@ +package routes_test + +import ( + "testing" + + "github.com/franela/goreq" + "github.com/stretchr/testify/require" + + "github.com/lavab/api/env" + "github.com/lavab/api/models" + "github.com/lavab/api/routes" +) + +func TestContactsPrepareAccount(t *testing.T) { + const ( + username = "jeremy-contacts" + password = "potato" + ) + + inviteToken := models.Token{ + Resource: models.MakeResource("", "test invite token"), + Type: "invite", + } + inviteToken.ExpireSoon() + + err := env.Tokens.Insert(inviteToken) + require.Nil(t, err) + + result1, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/accounts", + ContentType: "application/json", + Body: routes.AccountsCreateRequest{ + Username: username, + Password: password, + Token: inviteToken.ID, + }, + }.Do() + require.Nil(t, err) + + var response1 routes.AccountsCreateResponse + err = result1.Body.FromJsonTo(&response1) + require.Nil(t, err) + + require.True(t, response1.Success) + require.Equal(t, "A new account was successfully created", response1.Message) + require.NotEmpty(t, response1.Account.ID) + + accountID = response1.Account.ID + + request2, err := goreq.Request{ + Method: "POST", + Uri: server.URL + "/tokens", + ContentType: "application/json", + Body: routes.TokensCreateRequest{ + Username: username, + Password: password, + Type: "auth", + }, + }.Do() + require.Nil(t, err) + + var response2 routes.TokensCreateResponse + err = request2.Body.FromJsonTo(&response2) + require.Nil(t, err) + + require.True(t, response2.Success) + require.Equal(t, "Authentication successful", response2.Message) + require.NotEmpty(t, response2.Token.ID) + + authToken = response2.Token.ID +} + +func TestContactsCreate(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/contacts", + ContentType: "application/json", + Body: routes.ContactsCreateRequest{ + Data: "random stuff", + Name: "John Doe", + Encoding: "json", + VersionMajor: 1, + VersionMinor: 0, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "A new contact was successfully created", response.Message) + require.True(t, response.Success) + require.NotEmpty(t, response.Contact.ID) +} + +func TestContactsCreateMissingParts(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/contacts", + ContentType: "application/json", + Body: routes.ContactsCreateRequest{ + Data: "random stuff", + Name: "John Doe", + Encoding: "", + VersionMajor: 1, + VersionMinor: 0, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "Invalid request", response.Message) + require.False(t, response.Success) +} + +func TestContactsCreateInvalid(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/contacts", + ContentType: "application/json", + Body: "!@#!@#!@#", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "Invalid input format", response.Message) + require.False(t, response.Success) +} + +func TestContactsList(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/contacts", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsListResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.True(t, len(*response.Contacts) > 0) +} From 8a532ac6d55d1d4ef3331ce3fe4b74b409003870 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 29 Nov 2014 20:32:07 +0100 Subject: [PATCH 18/19] Contacts tests --- routes/contacts_test.go | 219 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) diff --git a/routes/contacts_test.go b/routes/contacts_test.go index 40f353f..e2a5ee7 100644 --- a/routes/contacts_test.go +++ b/routes/contacts_test.go @@ -11,6 +11,11 @@ import ( "github.com/lavab/api/routes" ) +var ( + contactID string + notOwnedContactID string +) + func TestContactsPrepareAccount(t *testing.T) { const ( username = "jeremy-contacts" @@ -95,6 +100,8 @@ func TestContactsCreate(t *testing.T) { require.Equal(t, "A new contact was successfully created", response.Message) require.True(t, response.Success) require.NotEmpty(t, response.Contact.ID) + + contactID = response.Contact.ID } func TestContactsCreateMissingParts(t *testing.T) { @@ -157,3 +164,215 @@ func TestContactsList(t *testing.T) { require.True(t, response.Success) require.True(t, len(*response.Contacts) > 0) } + +func TestContactsGet(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/contacts/" + contactID, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.Equal(t, "John Doe", response.Contact.Name) +} + +func TestContactsGetNotOwned(t *testing.T) { + contact := &models.Contact{ + Encrypted: models.Encrypted{ + Encoding: "json", + Data: "carp", + Schema: "contact", + VersionMajor: 1, + VersionMinor: 0, + }, + Resource: models.MakeResource("not", "Carpeus Caesar"), + } + + err := env.Contacts.Insert(contact) + require.Nil(t, err) + + notOwnedContactID = contact.ID + + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/contacts/" + contact.ID, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} + +func TestContactsGetWrongID(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/contacts/gibberish", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} + +func TestContactsUpdate(t *testing.T) { + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/contacts/" + contactID, + ContentType: "application/json", + Body: routes.ContactsUpdateRequest{ + Data: "random stuff2", + Name: "John Doez", + Encoding: "json", + VersionMajor: 1, + VersionMinor: 0, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.Equal(t, "John Doez", response.Contact.Name) +} + +func TestContactsUpdateInvalid(t *testing.T) { + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/contacts/" + contactID, + ContentType: "application/json", + Body: "123123!@#!@#", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Invalid input format", response.Message) +} + +func TestContactsUpdateNotOwned(t *testing.T) { + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/contacts/" + notOwnedContactID, + ContentType: "application/json", + Body: routes.ContactsUpdateRequest{ + Data: "random stuff2", + Name: "John Doez", + Encoding: "json", + VersionMajor: 1, + VersionMinor: 0, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} + +func TestContactsUpdateNotExisting(t *testing.T) { + request := goreq.Request{ + Method: "PUT", + Uri: server.URL + "/contacts/gibberish", + ContentType: "application/json", + Body: routes.ContactsUpdateRequest{ + Data: "random stuff2", + Name: "John Doez", + Encoding: "json", + VersionMajor: 1, + VersionMinor: 0, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsUpdateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} + +func TestContactsDelete(t *testing.T) { + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/contacts/" + contactID, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsDeleteResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.Equal(t, "Contact successfully removed", response.Message) +} + +func TestContactsDeleteNotOwned(t *testing.T) { + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/contacts/" + notOwnedContactID, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsDeleteResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} + +func TestContactsDeleteNotExisting(t *testing.T) { + request := goreq.Request{ + Method: "DELETE", + Uri: server.URL + "/contacts/gibberish", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.ContactsDeleteResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Contact not found", response.Message) +} From c881573ef388061fa117895526ce9706b1e65a9e Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 30 Nov 2014 01:21:40 +0100 Subject: [PATCH 19/19] Finishing tests package --- routes/accounts_test.go | 200 +++++++++++++++++++------------------- routes/hello_test.go | 4 +- routes/keys.go | 9 +- routes/keys_test.go | 195 +++++++++++++++++++++++++++++++++++++ routes/middleware_test.go | 91 +++++++++++++++++ routes/tokens_test.go | 34 +++---- 6 files changed, 405 insertions(+), 128 deletions(-) create mode 100644 routes/keys_test.go create mode 100644 routes/middleware_test.go diff --git a/routes/accounts_test.go b/routes/accounts_test.go index df78c66..6c07c8f 100644 --- a/routes/accounts_test.go +++ b/routes/accounts_test.go @@ -13,22 +13,20 @@ import ( ) func TestAccountsCreateInvalid(t *testing.T) { - // POST /accounts - invalid result, err := goreq.Request{ Method: "POST", Uri: server.URL + "/accounts", ContentType: "application/json", Body: "!@#!@#", }.Do() - require.Nil(t, err, "querying invalid /accounts should not return an error") + require.Nil(t, err) - // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) env.Log.Print(response) - require.Nil(t, err, "unmarshaling invalid account creation should not return an error") - require.False(t, response.Success, "request should fail") - require.Equal(t, "Invalid input format", response.Message, "proper message should be returned") + require.Nil(t, err) + require.False(t, response.Success) + require.Equal(t, "Invalid input format", response.Message) } func TestAccountsCreateUnknown(t *testing.T) { @@ -37,16 +35,16 @@ func TestAccountsCreateUnknown(t *testing.T) { Method: "POST", Uri: server.URL + "/accounts", }.Do() - require.Nil(t, err, "querying unknown /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check values - require.False(t, response.Success, "unknown request should return success false") - require.Equal(t, "Invalid request", response.Message, "unknown request should return proper error msg") + require.False(t, response.Success) + require.Equal(t, "Invalid request", response.Message) } func TestAccountsCreateInvited(t *testing.T) { @@ -63,7 +61,7 @@ func TestAccountsCreateInvited(t *testing.T) { inviteToken.ExpireSoon() err := env.Tokens.Insert(inviteToken) - require.Nil(t, err, "inserting a new invitation token should not return an error") + require.Nil(t, err) // POST /accounts - invited result1, err := goreq.Request{ @@ -76,17 +74,17 @@ func TestAccountsCreateInvited(t *testing.T) { Token: inviteToken.ID, }, }.Do() - require.Nil(t, err, "querying invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response1 routes.AccountsCreateResponse err = result1.Body.FromJsonTo(&response1) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, response1.Success, "creating a new account using inv registration failed") - require.Equal(t, "A new account was successfully created", response1.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, response1.Account.ID, "newly created account's id should not be empty") + require.True(t, response1.Success) + require.Equal(t, "A new account was successfully created", response1.Message) + require.NotEmpty(t, response1.Account.ID) accountID = response1.Account.ID @@ -101,16 +99,16 @@ func TestAccountsCreateInvited(t *testing.T) { Token: "asdasdasd", }, }.Do() - require.Nil(t, err, "querying invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response2 routes.AccountsCreateResponse err = result2.Body.FromJsonTo(&response2) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, response2.Success, "creating a new account using invalid token should fail") - require.Equal(t, "Invalid invitation token", response2.Message, "invalid message returned by invalid token acc creation") + require.False(t, response2.Success) + require.Equal(t, "Invalid invitation token", response2.Message) } func TestAccountsCreateInvitedExisting(t *testing.T) { @@ -127,7 +125,7 @@ func TestAccountsCreateInvitedExisting(t *testing.T) { inviteToken.ExpireSoon() err := env.Tokens.Insert(inviteToken) - require.Nil(t, err, "inserting a new invitation token should not return an error") + require.Nil(t, err) // POST /accounts - invited result, err := goreq.Request{ @@ -140,16 +138,16 @@ func TestAccountsCreateInvitedExisting(t *testing.T) { Token: inviteToken.ID, }, }.Do() - require.Nil(t, err, "querying existing invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling existing invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "creating a new account using inv registration should fail") - require.Equal(t, "Username already exists", response.Message, "invalid message returned by existing invited acc creation") + require.False(t, response.Success) + require.Equal(t, "Username already exists", response.Message) } func TestAccountsCreateInvitedExpired(t *testing.T) { @@ -166,7 +164,7 @@ func TestAccountsCreateInvitedExpired(t *testing.T) { inviteToken.ExpiryDate = time.Now().Truncate(time.Hour) err := env.Tokens.Insert(inviteToken) - require.Nil(t, err, "inserting a new invitation token should not return an error") + require.Nil(t, err) // POST /accounts - invited result, err := goreq.Request{ @@ -179,16 +177,16 @@ func TestAccountsCreateInvitedExpired(t *testing.T) { Token: inviteToken.ID, }, }.Do() - require.Nil(t, err, "querying expired invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling expired invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "creating a new account using inv registration should fail") - require.Equal(t, "Expired invitation token", response.Message, "invalid message returned by expired invited acc creation") + require.False(t, response.Success) + require.Equal(t, "Expired invitation token", response.Message) } func TestAccountsCreateInvitedWrongType(t *testing.T) { @@ -205,7 +203,7 @@ func TestAccountsCreateInvitedWrongType(t *testing.T) { inviteToken.ExpiryDate = time.Now().Truncate(time.Hour) err := env.Tokens.Insert(inviteToken) - require.Nil(t, err, "inserting a new not invitation token should not return an error") + require.Nil(t, err) // POST /accounts - invited result, err := goreq.Request{ @@ -218,16 +216,16 @@ func TestAccountsCreateInvitedWrongType(t *testing.T) { Token: inviteToken.ID, }, }.Do() - require.Nil(t, err, "querying wrong type invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling wrong type invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "creating a new account using inv registration should fail") - require.Equal(t, "Invalid invitation token", response.Message, "invalid message returned by wrong type invited acc creation") + require.False(t, response.Success) + require.Equal(t, "Invalid invitation token", response.Message) } func TestAccountsCreateClassic(t *testing.T) { @@ -247,17 +245,17 @@ func TestAccountsCreateClassic(t *testing.T) { AltEmail: "something@example.com", }, }.Do() - require.Nil(t, err, "querying invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var createClassicResponse routes.AccountsCreateResponse err = createClassicResult.Body.FromJsonTo(&createClassicResponse) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, createClassicResponse.Success, "creating a new account using classic registration failed") - require.Equal(t, "A new account was successfully created, you should receive a confirmation email soon™.", createClassicResponse.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, createClassicResponse.Account.ID, "newly created account's id should not be empty") + require.True(t, createClassicResponse.Success) + require.Equal(t, "A new account was successfully created, you should receive a confirmation email soon™.", createClassicResponse.Message) + require.NotEmpty(t, createClassicResponse.Account.ID) } func TestAccountsCreateClassicDisabled(t *testing.T) { @@ -279,16 +277,16 @@ func TestAccountsCreateClassicDisabled(t *testing.T) { AltEmail: "something@example.com", }, }.Do() - require.Nil(t, err, "querying invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var createClassicResponse routes.AccountsCreateResponse err = createClassicResult.Body.FromJsonTo(&createClassicResponse) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, createClassicResponse.Success, "creating a new account using classic registration failed") - require.Equal(t, "Classic registration is disabled", createClassicResponse.Message, "invalid message returned by invited acc creation") + require.False(t, createClassicResponse.Success) + require.Equal(t, "Classic registration is disabled", createClassicResponse.Message) env.Config.ClassicRegistration = true } @@ -303,16 +301,16 @@ func TestAccountsCreateQueue(t *testing.T) { AltEmail: "something@example.com", }, }.Do() - require.Nil(t, err, "querying /accounts to queue") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsCreateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling queue response create should not fail") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "creating a new account using queue registration failed") - require.Equal(t, "Sorry, not implemented yet", response.Message, "invalid message returned by queue acc creation") + require.False(t, response.Success) + require.Equal(t, "Sorry, not implemented yet", response.Message) } func TestAccountsPrepareToken(t *testing.T) { @@ -332,17 +330,17 @@ func TestAccountsPrepareToken(t *testing.T) { Type: "auth", }, }.Do() - require.Nil(t, err, "querying existing /tokens should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.TokensCreateResponse err = request.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, response.Success, "creating a new token using existing account failed") - require.Equal(t, "Authentication successful", response.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, response.Token.ID, "newly created token's id should not be empty") + require.True(t, response.Success) + require.Equal(t, "Authentication successful", response.Message) + require.NotEmpty(t, response.Token.ID) // Populate the global token variable authToken = response.Token.ID @@ -356,16 +354,16 @@ func TestAccountsList(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "querying /accounts should not fail") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsListResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling queue response create should not fail") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "creating a new account using queue registration failed") - require.Equal(t, "Sorry, not implemented yet", response.Message, "invalid message returned by queue acc creation") + require.False(t, response.Success) + require.Equal(t, "Sorry, not implemented yet", response.Message) } func TestAccountsGetMe(t *testing.T) { @@ -376,16 +374,16 @@ func TestAccountsGetMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "querying /accounts/me should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsGetResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling /accounts/me should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, response.Success, "getting /accounts/me should succeed") - require.Equal(t, "jeremy", response.Account.Name, "username should be the previously registered one") + require.True(t, response.Success) + require.Equal(t, "jeremy", response.Account.Name) } func TestAccountsGetNotMe(t *testing.T) { @@ -395,16 +393,16 @@ func TestAccountsGetNotMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "querying /accounts/not-me should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsGetResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling /accounts/not-me should not return an error") + require.Nil(t, err) // Check the result's contents - require.False(t, response.Success, "getting /accounts/not-me should fail") - require.Equal(t, `Only the "me" user is implemented`, response.Message, "/accounts/not-me should return a proper message") + require.False(t, response.Success) + require.Equal(t, `Only the "me" user is implemented`, response.Message) } func TestAccountUpdateMe(t *testing.T) { @@ -421,18 +419,18 @@ func TestAccountUpdateMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "updating account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsUpdateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account update response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, "Your account has been successfully updated", response.Message, "response message should be valid") - require.True(t, response.Success, "updating /accounts/me should succeed") - require.Equal(t, "jeremy", response.Account.Name, "username should not be changed") - require.Equal(t, "john.cabbage@example.com", response.Account.AltEmail, "alt email should be changed") + require.Equal(t, "Your account has been successfully updated", response.Message) + require.True(t, response.Success) + require.Equal(t, "jeremy", response.Account.Name) + require.Equal(t, "john.cabbage@example.com", response.Account.AltEmail) } func TestAccountUpdateInvalid(t *testing.T) { @@ -445,16 +443,16 @@ func TestAccountUpdateInvalid(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "updating account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsUpdateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account update response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, "Invalid input format", response.Message, "response message should be valid") - require.False(t, response.Success, "updating invalid /accounts/me should fail") + require.Equal(t, "Invalid input format", response.Message) + require.False(t, response.Success) } func TestAccountUpdateNotMe(t *testing.T) { @@ -471,16 +469,16 @@ func TestAccountUpdateNotMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "updating account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsUpdateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account update response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") - require.False(t, response.Success, "updating /accounts/not-me should fail") + require.Equal(t, `Only the "me" user is implemented`, response.Message) + require.False(t, response.Success) } func TestAccountUpdateMeInvalidPassword(t *testing.T) { @@ -497,16 +495,16 @@ func TestAccountUpdateMeInvalidPassword(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "updating account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsUpdateResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account update response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, "Invalid current password", response.Message, "response message should be valid") - require.False(t, response.Success, "updating /accounts/me should fail") + require.Equal(t, "Invalid current password", response.Message) + require.False(t, response.Success) } func TestAccountsWipeDataNotMe(t *testing.T) { @@ -517,16 +515,16 @@ func TestAccountsWipeDataNotMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "wiping account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsWipeDataResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account wipe response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") - require.False(t, response.Success, "triggering /accounts/wipe-data should fail") + require.Equal(t, `Only the "me" user is implemented`, response.Message) + require.False(t, response.Success) } func TestAccountsWipeData(t *testing.T) { @@ -537,16 +535,16 @@ func TestAccountsWipeData(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "wiping account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsWipeDataResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account wipe response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, "Your account has been successfully wiped", response.Message, "response message should be valid") - require.True(t, response.Success, "triggering /accounts/wipe-data should succeed") + require.Equal(t, "Your account has been successfully wiped", response.Message) + require.True(t, response.Success) } func TestAccountsDeleteNotMe(t *testing.T) { @@ -558,7 +556,7 @@ func TestAccountsDeleteNotMe(t *testing.T) { token.ExpireSoon() err := env.Tokens.Insert(token) - require.Nil(t, err, "inserting a new auth toekn token should not return an error") + require.Nil(t, err) // DELETE /accounts/me request := goreq.Request{ @@ -567,16 +565,16 @@ func TestAccountsDeleteNotMe(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+token.ID) result, err := request.Do() - require.Nil(t, err, "deleting account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsWipeDataResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account delete response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, `Only the "me" user is implemented`, response.Message, "response message should be valid") - require.False(t, response.Success, "triggering delete /account/me should fail") + require.Equal(t, `Only the "me" user is implemented`, response.Message) + require.False(t, response.Success) } func TestAccountsDelete(t *testing.T) { @@ -588,7 +586,7 @@ func TestAccountsDelete(t *testing.T) { token.ExpireSoon() err := env.Tokens.Insert(token) - require.Nil(t, err, "inserting a new auth toekn token should not return an error") + require.Nil(t, err) // DELETE /accounts/me request := goreq.Request{ @@ -597,14 +595,14 @@ func TestAccountsDelete(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+token.ID) result, err := request.Do() - require.Nil(t, err, "deleting account should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.AccountsWipeDataResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling account delete response should not return an error") + require.Nil(t, err) // Check the result's contents - require.Equal(t, "Your account has been successfully deleted", response.Message, "response message should be valid") - require.True(t, response.Success, "triggering delete /account/me should succeed") + require.Equal(t, "Your account has been successfully deleted", response.Message) + require.True(t, response.Success) } diff --git a/routes/hello_test.go b/routes/hello_test.go index 061dc81..7f05bf4 100644 --- a/routes/hello_test.go +++ b/routes/hello_test.go @@ -15,11 +15,11 @@ func TestHello(t *testing.T) { Method: "GET", Uri: server.URL, }.Do() - require.Nil(t, err, "requesting / should not return an error") + require.Nil(t, err) // Unmarshal the response var helloResponse routes.HelloResponse err = helloResult.Body.FromJsonTo(&helloResponse) - require.Nil(t, err, "unmarshaling / result should not return an error") + require.Nil(t, err) require.Equal(t, "Lavaboom API", helloResponse.Message) } diff --git a/routes/keys.go b/routes/keys.go index a6ea771..980f705 100644 --- a/routes/keys.go +++ b/routes/keys.go @@ -179,14 +179,7 @@ type KeysGetResponse struct { // KeysGet does *something* - TODO func KeysGet(c web.C, w http.ResponseWriter, r *http.Request) { // Get ID from the passed URL params - id, ok := c.URLParams["id"] - if !ok { - utils.JSONResponse(w, 404, &KeysGetResponse{ - Success: false, - Message: "Requested key does not exist on our server", - }) - return - } + id := c.URLParams["id"] // Fetch the requested key from the database key, err := env.Keys.FindByFingerprint(id) diff --git a/routes/keys_test.go b/routes/keys_test.go new file mode 100644 index 0000000..32b5e81 --- /dev/null +++ b/routes/keys_test.go @@ -0,0 +1,195 @@ +package routes_test + +import ( + "testing" + + "github.com/franela/goreq" + "github.com/lavab/api/routes" + "github.com/stretchr/testify/require" +) + +var ( + keyID string +) + +func TestKeysCreate(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/keys", + ContentType: "application/json", + Body: routes.KeysCreateRequest{ + Key: `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQINBFR6JFoBEADoLOVi5NEkIELYOIfOsztAuPqNPiJcDXCsKuprjNj7n2vxyNim +WbArRZ4TJereG0H2skCQlKMx26EiHHdK3je4i6erD+OT4NolAsxVsl4PpkEDZnzz +tIwVb7FymahIrqwP9YPrXc0tr07HgnE3+it828ZJlCMfGUgJJrn12p+UetlBoFwr +OEgaCl4fOfAuUQUzD156AGV/S0H4ge8H7yngSxNTMCqypX6SaX+O0uhKqa3CxiiG +HxIGo+lNdM72Xm3Ym9sNKtfsflkqZdlWfdpit1mgveZMx2CpuYI1aS+FRzQczCDn +fDnSVqErIWUv64daC5qU3pPWjqRuOr4WXEdxXSCgi2oXVP+2hVyqgPk6ch64TodR +lKxFN2wvrJVYJd/5XQrojBtf/F/ZnlYq0rze+snZ5R1lBMZMU2oBnWtRQMSO/+8b +iHY/7mjyT+LGLXhbGGmgtycYsuujR54Smtzx1tc7CsoVLJ3JB4629YT6RtDnd85R +f7oUnjtd714e6k6zLIkppsSDse8WOPGtnfHxswrNRGnEPFYxQhCN+PbYdwGmSfmA +kzoJFumJF8KIXflGBZ0s2JdAx4G1aMhPR3rUNiJdh+DXXseLn/PAbDj2O4uMVi5F +/ai6U/vhNOatrt5syOwWZnShuIBj5VwwyJOdGjC9uwYrfocDtx7IdbaokQARAQAB +tCFQaW90ciBaZHVuaWFrIDxwaW90ckB6ZHVuaWFrLm5ldD6JAjgEEwECACIFAlR6 +JFoCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEN9g3PR+HyAlZigP/3H2 +l9icK0tazF5B4jcPaKJ4cToe/XiTU1eNNzTGftlbtCgb2e2TMuzcY7LpiK3zHO5z +0NlVKWxAoD7JHEaG5vwL74gB1324VbW08dWcz/a/jMyTAUhGIZ1WBIJGa9dVkN98 +GZp6i8q2DfsvflQI5Q9s3+Y6nbl2FEDFc3U+UXyN3M7x94NEc+3BUPvds/CwD/L0 +rjatqusCf1lo2GNZvVcoluerKjSR0/LryTbQwSlW0rDIVAoc5AB1ezpJKfW6O22i +4h8MpNGNJ3XVrMIX4/Tu4ESE75WQSVqThd1Zy3y9bVvhL8UxKV3qviuBRDtlk/7N +QznUBTJ0RFegebTDp6+jVaVt+RBJg8rnwXOT0iSEBionCjjuIWX7hzM3mRg8FnnJ +RUudJxN2b1mJHKCHEG3/SIbl6m32HesJahfNnmGV8xs7YpZWHQU+DXoTJN8+t/2E +kZ7+4X38jdWfLfw4Z+Cb3J+J4yf0uipUQ8+6f7zm2p0BINlt5TQczZpWYQolhKoK +Xhd+Sd2XieaAkxUQqaYjCbr5fC5QouWYlwqnghCVSs1MLCPdHDI2FOXB5Sh8hOHN +sxar+5r9iWLkAvr5k+QoR8fQgarIQKcXQc+NQR65D8eneGo/apVknvRVMLrtC1ZI +QLi8aLMFaM6HReXsHD6PJUsuuHys2fhT+6vD4ujjuQINBFR6JFoBEADMa8xp8O1W +WvRxBZ0Bd0EOm+znhCsDhdHxrq3x74k3229NVJ42tfRunegP+s+/nFQuSV/FXxiL +NFb7cfTL2ZlibNbOwbZ6RQ66BdPaBKyIc0QdIsaR/+ehGqbG0dN1aAiQJBustPzX +RQJBhzHKx4FpdJLrFppe5JLp2pcmI9CoMHdirIh3uFF85sNBTa0MAHNBHzXBeZbv +jZDCxTkFBPmUEbNiUWDOPDQnZlJAG9VvXzSLilsZ4Cgj/jN0/MUJ+vEOb1NvOWNH +Wo0/uFqmMhAFHxFSUETnZ4Q/6ZU2bdCeAp9uo1oEFvaEbmRdW1BkjMOXqJ4V5bXj +p9qREraEargj3+FKQHIiKDEz6p4C9y0RsJROIj8oZmvZsynzsnrmU5Gme5V8a4sS +ruPkm3kmdPCWq1SSZ/3V293NnE73KKdy6XinuyZBWVN1y8jSd/lJpyIZzIIMAQSp +OwWBYnVwTIlbFi0Ad1BGvMMSCM15AdrN9Ywb7xfnlkXEMHTQk4czwJUDKYodIw1u +KnGm/N/SPlgm1sk59rlMTQk0/TFT6KsYEoDdEJP934lldG+11vgpcicV8owM0AQ4 +PYtVTKhHv7QNK0FCIHWIWq/QMLJn73X7kotgLB/1M94eTgcWasg4ENI/ZCCRelnL +6cs4Ggo4/j/bd5QhogdiJYHUlEDqUL+a0QARAQABiQIfBBgBAgAJBQJUeiRaAhsM +AAoJEN9g3PR+HyAled0P/0J9gp48UOSWmkoMOPbGCIyABYMmaoDKdYYf1rToP3wp +O2nOwG48ZFW9Q4r6LAiOmPjPtMsvjtFeHDQ5FjnXpbFI2NBn3YwB2fulim8TZL03 +SvpiZD7TUiZKmUAOmVPoZJ+GUIE9lJtBrlOS5n0TkhmS14G3xPlex7jdJ63JFmME +XZ9gDcgUOzG7pSneCYyHOLKGwTmLV3HXUSIAm/8bW2xJ7g+j9qr/c78D8ThUY+I0 +0edCq+tL5rpnPYIusI3lzh4xeSMSSVCKB+Fhz9DFdD6pZC6E6KWlaoUgw1DdvfFC +KFrEhGFPu80Y7zl77nME9Yg9JYrKlISZHtbT8mDduOXlJIyZxsIlg/bDhsN38HOE +3ZoAsJh/8Ui44b58x/u4P9uKDroCua/6sOb0JFuxPNZHc7Sjdy1S0md7YEW3vFyT +1H1XzRAOPLwJFoz4ymRz9COHTyzExycr/TIjoBG7v1nYOGUdqaTNU2/802LRQaE2 +eUftQWTTiFoES4Z0vTKmKwq3CoP80Z5zTrcQf8CdMmTd9bu9kE3AvrK6OD0amxKw +LNHuuVgP/KuG0U4M8A641mUjCt0ZvtDCcAgO90cQKdHsuiCkX/wFYGg+lCzwjtRZ +UZSWZtUmAO12vjmUwGtRbp5xfdbV+PmIBRYe0iikrykoBy+FLw9yHlSCoey2ih6W +=r/yh +-----END PGP PUBLIC KEY BLOCK-----`, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "A new key has been successfully inserted", response.Message) + require.True(t, response.Success) + require.NotEmpty(t, response.Key.ID) + + keyID = response.Key.ID +} + +func TestKeysCreateInvalid(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/keys", + ContentType: "application/json", + Body: "!@#!@!@#", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "Invalid input format", response.Message) + require.False(t, response.Success) +} + +func TestKeysCreateWrongKey(t *testing.T) { + request := goreq.Request{ + Method: "POST", + Uri: server.URL + "/keys", + ContentType: "application/json", + Body: routes.KeysCreateRequest{ + Key: `hbnjmvnbhvm nbhm jhbjmnghnbgjvgbhvf bgvmj gvhnft`, + }, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysCreateResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.Equal(t, "Invalid key format", response.Message) + require.False(t, response.Success) +} + +func TestKeysList(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/keys?user=jeremy-contacts", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysListResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.True(t, len(*response.Keys) > 0) +} + +func TestKeysListNoUsername(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/keys", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysListResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Invalid username", response.Message) +} + +func TestKeysGet(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/keys/" + keyID, + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.True(t, response.Success) + require.Equal(t, keyID, response.Key.ID) +} + +func TestKeyGetInvalid(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/keys/123", + } + request.AddHeader("Authorization", "Bearer "+authToken) + result, err := request.Do() + require.Nil(t, err) + + var response routes.KeysGetResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Requested key does not exist on our server", response.Message) +} diff --git a/routes/middleware_test.go b/routes/middleware_test.go new file mode 100644 index 0000000..5680885 --- /dev/null +++ b/routes/middleware_test.go @@ -0,0 +1,91 @@ +package routes_test + +import ( + "testing" + "time" + + "github.com/franela/goreq" + "github.com/stretchr/testify/require" + + "github.com/lavab/api/env" + "github.com/lavab/api/models" + "github.com/lavab/api/routes" +) + +func TestMiddlewareNoHeader(t *testing.T) { + result, err := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/me", + }.Do() + require.Nil(t, err) + + var response routes.AuthMiddlewareResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Missing auth token", response.Message) +} + +func TestMiddlewareInvalidHeader(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/me", + } + request.AddHeader("Authorization", "123") + result, err := request.Do() + require.Nil(t, err) + + var response routes.AuthMiddlewareResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Invalid authorization header", response.Message) +} + +func TestMiddlewareInvalidToken(t *testing.T) { + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/me", + } + request.AddHeader("Authorization", "Bearer 123") + result, err := request.Do() + require.Nil(t, err) + + var response routes.AuthMiddlewareResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Invalid authorization token", response.Message) +} + +func TestMiddlewareExpiredToken(t *testing.T) { + // Prepare a token + token := models.Token{ + Resource: models.MakeResource(accountID, "test invite token"), + Expiring: models.Expiring{ + ExpiryDate: time.Now().UTC().Truncate(time.Hour * 8), + }, + Type: "auth", + } + + err := env.Tokens.Insert(token) + require.Nil(t, err) + + request := goreq.Request{ + Method: "GET", + Uri: server.URL + "/accounts/me", + } + request.AddHeader("Authorization", "Bearer "+token.ID) + result, err := request.Do() + require.Nil(t, err) + + var response routes.AuthMiddlewareResponse + err = result.Body.FromJsonTo(&response) + require.Nil(t, err) + + require.False(t, response.Success) + require.Equal(t, "Authorization token has expired", response.Message) +} diff --git a/routes/tokens_test.go b/routes/tokens_test.go index 87755da..6fcf270 100644 --- a/routes/tokens_test.go +++ b/routes/tokens_test.go @@ -26,7 +26,7 @@ func TestTokensPrepareAccount(t *testing.T) { inviteToken.ExpireSoon() err := env.Tokens.Insert(inviteToken) - require.Nil(t, err, "inserting a new invitation token should not return an error") + require.Nil(t, err) // POST /accounts - invited result1, err := goreq.Request{ @@ -39,17 +39,17 @@ func TestTokensPrepareAccount(t *testing.T) { Token: inviteToken.ID, }, }.Do() - require.Nil(t, err, "querying invited /accounts should not return an error") + require.Nil(t, err) // Unmarshal the response var response1 routes.AccountsCreateResponse err = result1.Body.FromJsonTo(&response1) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, response1.Success, "creating a new account using inv registration failed") - require.Equal(t, "A new account was successfully created", response1.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, response1.Account.ID, "newly created account's id should not be empty") + require.True(t, response1.Success) + require.Equal(t, "A new account was successfully created", response1.Message) + require.NotEmpty(t, response1.Account.ID) accountID = response1.Account.ID } @@ -71,17 +71,17 @@ func TestTokensCreate(t *testing.T) { Type: "auth", }, }.Do() - require.Nil(t, err, "querying existing /tokens should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.TokensCreateResponse err = request.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents - require.True(t, response.Success, "creating a new token using existing account failed") - require.Equal(t, "Authentication successful", response.Message, "invalid message returned by invited acc creation") - require.NotEmpty(t, response.Token.ID, "newly created token's id should not be empty") + require.True(t, response.Success) + require.Equal(t, "Authentication successful", response.Message) + require.NotEmpty(t, response.Token.ID) // Populate the global token variable authToken = response.Token.ID @@ -155,12 +155,12 @@ func TestTokensCreateInvalid(t *testing.T) { ContentType: "application/json", Body: "123123123###434$#$", }.Do() - require.Nil(t, err, "querying existing /tokens should not return an error") + require.Nil(t, err) // Unmarshal the response var response routes.TokensCreateResponse err = request.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling invited account creation should not return an error") + require.Nil(t, err) // Check the result's contents require.False(t, response.Success) @@ -174,14 +174,14 @@ func TestTokensGet(t *testing.T) { } request.AddHeader("Authorization", "Bearer "+authToken) result, err := request.Do() - require.Nil(t, err, "qurying /tokens should not return an error") + require.Nil(t, err) var response routes.TokensGetResponse err = result.Body.FromJsonTo(&response) - require.Nil(t, err, "unmarshaling should not return an error") + require.Nil(t, err) - require.True(t, response.Success, "request should be successful") - require.True(t, response.Expires.After(time.Now().UTC()), "expiry time has to be valid") + require.True(t, response.Success) + require.True(t, response.Expires.After(time.Now().UTC())) } func TestTokensDeleteById(t *testing.T) {