- Modify scenario testing

- Add scenario validators
- Clean up responses and serializes with respect to scenario
- Fix error handling and responses of scenario endpoints
This commit is contained in:
Sonja Happ 2019-09-04 16:31:20 +02:00
parent 46e84fc758
commit 2772bde5ee
8 changed files with 634 additions and 191 deletions

View file

@ -5,11 +5,10 @@ import "github.com/jinzhu/gorm/dialects/postgres"
type KeyModels map[string]interface{} type KeyModels map[string]interface{}
type Request struct { type Request struct {
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
Mail string `json:"mail,omitempty"` Mail string `json:"mail,omitempty"`
Role string `json:"role,omitempty"` Role string `json:"role,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Running bool `json:"running,omitempty"` Running bool `json:"running,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`

View file

@ -2,13 +2,6 @@ package common
import "github.com/jinzhu/gorm/dialects/postgres" import "github.com/jinzhu/gorm/dialects/postgres"
type ScenarioResponse struct {
Name string `json:"name"`
ID uint `json:"id"`
Running bool `json:"running"`
StartParameters postgres.Jsonb `json:"startParameters"`
}
type SimulationModelResponse struct { type SimulationModelResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@ -80,14 +73,6 @@ type ResponseMsg struct {
Message string `json:"message"` Message string `json:"message"`
} }
type ResponseMsgScenarios struct {
Scenarios []ScenarioResponse `json:"scenarios"`
}
type ResponseMsgScenario struct {
Scenario ScenarioResponse `json:"scenario"`
}
type ResponseMsgSimulationModels struct { type ResponseMsgSimulationModels struct {
SimulationModels []SimulationModelResponse `json:"models"` SimulationModels []SimulationModelResponse `json:"models"`
} }

View file

@ -4,37 +4,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// Scenario/s Serializers
type ScenariosSerializer struct {
Ctx *gin.Context
Scenarios []Scenario
}
func (self *ScenariosSerializer) Response() []ScenarioResponse {
response := []ScenarioResponse{}
for _, so := range self.Scenarios {
serializer := ScenarioSerializer{self.Ctx, so}
response = append(response, serializer.Response())
}
return response
}
type ScenarioSerializer struct {
Ctx *gin.Context
Scenario
}
func (self *ScenarioSerializer) Response() ScenarioResponse {
response := ScenarioResponse{
Name: self.Name,
ID: self.ID,
Running: self.Running,
StartParameters: self.StartParameters,
}
return response
}
// Model/s Serializers // Model/s Serializers
type SimulationModelsSerializer struct { type SimulationModelsSerializer struct {

View file

@ -154,13 +154,7 @@ var startParametersB = json.RawMessage(`{"parameter1" : "testValue1B", "paramete
var startParametersC = json.RawMessage(`{"parameter1" : "testValue1C", "parameter2" : "testValue2C", "parameter3" : 44}`) var startParametersC = json.RawMessage(`{"parameter1" : "testValue1C", "parameter2" : "testValue2C", "parameter3" : 44}`)
var ScenarioA = Scenario{Name: "Scenario_A", Running: true, StartParameters: postgres.Jsonb{startParametersA}} var ScenarioA = Scenario{Name: "Scenario_A", Running: true, StartParameters: postgres.Jsonb{startParametersA}}
var ScenarioA_response = ScenarioResponse{ID: 1, Name: ScenarioA.Name, Running: ScenarioA.Running, StartParameters: ScenarioA.StartParameters}
var ScenarioB = Scenario{Name: "Scenario_B", Running: false, StartParameters: postgres.Jsonb{startParametersB}} var ScenarioB = Scenario{Name: "Scenario_B", Running: false, StartParameters: postgres.Jsonb{startParametersB}}
var ScenarioB_response = ScenarioResponse{ID: 2, Name: ScenarioB.Name, Running: ScenarioB.Running, StartParameters: ScenarioB.StartParameters}
var ScenarioC = Scenario{Name: "Scenario_C", Running: false, StartParameters: postgres.Jsonb{startParametersC}}
var ScenarioC_response = ScenarioResponse{ID: 3, Name: ScenarioC.Name, Running: ScenarioC.Running, StartParameters: ScenarioC.StartParameters}
var ScenarioCUpdated = Scenario{Name: "Scenario_Cupdated", Running: true, StartParameters: postgres.Jsonb{startParametersC}}
var ScenarioCUpdated_response = ScenarioResponse{ID: 3, Name: ScenarioCUpdated.Name, Running: ScenarioCUpdated.Running, StartParameters: ScenarioCUpdated.StartParameters}
// Simulation Models // Simulation Models

View file

@ -1,6 +1,7 @@
package scenario package scenario
import ( import (
"fmt"
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -64,9 +65,8 @@ func getScenarios(c *gin.Context) {
} }
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario
serializer := common.ScenariosSerializer{c, scenarios}
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"scenarios": serializer.Response(), "scenarios": scenarios,
}) })
} }
@ -98,35 +98,44 @@ func addScenario(c *gin.Context) {
return return
} }
var newScenarioData common.ResponseMsgScenario var req addScenarioRequest
err = c.BindJSON(&newScenarioData) if err := c.ShouldBindJSON(&req); err != nil {
if err != nil {
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
c.JSON(http.StatusBadRequest, gin.H{ c.JSON(http.StatusBadRequest, gin.H{
"error": errormsg, "success": false,
"message": fmt.Sprintf("%v", err),
}) })
return return
} }
var newScenario Scenario // Validate the request
newScenario.ID = newScenarioData.Scenario.ID if err = req.validate(); err != nil {
newScenario.StartParameters = newScenarioData.Scenario.StartParameters c.JSON(http.StatusUnprocessableEntity, gin.H{
newScenario.Running = newScenarioData.Scenario.Running "success": false,
newScenario.Name = newScenarioData.Scenario.Name "message": fmt.Sprintf("%v", err),
})
return
}
// save new scenario to DB // Create the new scenario from the request
newScenario := req.createScenario()
// Save the new scenario in the DB
err = newScenario.save() err = newScenario.save()
if common.ProvideErrorResponse(c, err) { if err != nil {
common.ProvideErrorResponse(c, err)
return return
} }
// add user to new scenario // add user to new scenario
err = newScenario.addUser(&(u.User)) err = newScenario.addUser(&(u.User))
if common.ProvideErrorResponse(c, err) == false { if err != nil {
c.JSON(http.StatusOK, gin.H{ common.ProvideErrorResponse(c, err)
"message": "OK.", return
})
} }
c.JSON(http.StatusOK, gin.H{
"scenario": newScenario.Scenario,
})
} }
// updateScenario godoc // updateScenario godoc
@ -145,27 +154,50 @@ func addScenario(c *gin.Context) {
// @Router /scenarios/{scenarioID} [put] // @Router /scenarios/{scenarioID} [put]
func updateScenario(c *gin.Context) { func updateScenario(c *gin.Context) {
ok, so := CheckPermissions(c, common.Update, "path", -1) ok, oldScenario := CheckPermissions(c, common.Update, "path", -1)
if !ok { if !ok {
return return
} }
var modifiedScenarioData common.ResponseMsgScenario // Bind the (context) with the updateScenarioRequest struct
err := c.BindJSON(&modifiedScenarioData) var req updateScenarioRequest
if err != nil { if err := c.ShouldBindJSON(&req); err != nil {
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
c.JSON(http.StatusBadRequest, gin.H{ c.JSON(http.StatusBadRequest, gin.H{
"error": errormsg, "success": false,
"message": fmt.Sprintf("%v", err),
}) })
return return
} }
err = so.update(modifiedScenarioData.Scenario) // Validate the request based on struct updateScenarioRequest json tags
if common.ProvideErrorResponse(c, err) == false { if err := req.validate(); err != nil {
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusBadRequest, gin.H{
"message": "OK.", "success": false,
"message": fmt.Sprintf("%v", err),
}) })
return
} }
// Create the updatedScenario from oldScenario
updatedScenario, err := req.updatedScenario(oldScenario)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": fmt.Sprintf("%v", err),
})
return
}
// Finally update the scenario
err = oldScenario.update(updatedScenario)
if err != nil {
common.ProvideErrorResponse(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"scenario": updatedScenario.Scenario,
})
} }
// getScenario godoc // getScenario godoc
@ -188,9 +220,8 @@ func getScenario(c *gin.Context) {
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario
serializer := common.ScenarioSerializer{c, so.Scenario}
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"scenario": serializer.Response(), "scenario": so.Scenario,
}) })
} }
@ -214,11 +245,14 @@ func deleteScenario(c *gin.Context) {
} }
err := so.delete() err := so.delete()
if common.ProvideErrorResponse(c, err) == false { if err != nil {
c.JSON(http.StatusOK, gin.H{ common.ProvideErrorResponse(c, err)
"message": "OK.", return
})
} }
c.JSON(http.StatusOK, gin.H{
"scenario": so.Scenario,
})
} }
// getUsersOfScenario godoc // getUsersOfScenario godoc
@ -283,7 +317,7 @@ func addUserToScenario(c *gin.Context) {
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "OK.", "user": u.User,
}) })
} }
@ -309,12 +343,18 @@ func deleteUserFromScenario(c *gin.Context) {
username := c.Request.URL.Query().Get("username") username := c.Request.URL.Query().Get("username")
err := so.deleteUser(username) var u user.User
err := u.ByUsername(username)
if common.ProvideErrorResponse(c, err) {
return
}
err = so.deleteUser(username)
if common.ProvideErrorResponse(c, err) { if common.ProvideErrorResponse(c, err) {
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "OK.", "user": u.User,
}) })
} }

View file

@ -2,9 +2,9 @@ package scenario
import ( import (
"fmt" "fmt"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
"github.com/jinzhu/gorm"
) )
type Scenario struct { type Scenario struct {
@ -15,7 +15,7 @@ func (s *Scenario) ByID(id uint) error {
db := common.GetDB() db := common.GetDB()
err := db.Find(s, id).Error err := db.Find(s, id).Error
if err != nil { if err != nil {
return fmt.Errorf("scenario with id=%v does not exist", id) return err
} }
return nil return nil
} }
@ -33,9 +33,15 @@ func (s *Scenario) save() error {
return err return err
} }
func (s *Scenario) update(modifiedScenario common.ScenarioResponse) error { func (s *Scenario) update(updatedScenario Scenario) error {
// TODO: if the field is empty member shouldn't be updated
s.Name = updatedScenario.Name
s.Running = updatedScenario.Running
s.StartParameters = updatedScenario.StartParameters
db := common.GetDB() db := common.GetDB()
err := db.Model(s).Update(modifiedScenario).Error err := db.Model(s).Update(updatedScenario).Error
return err return err
} }
@ -69,7 +75,17 @@ func (s *Scenario) deleteUser(username string) error {
return err return err
} }
} else { } else {
return fmt.Errorf("cannot delete last user from scenario without deleting scenario itself, doing nothing") // There is only one associated user
var remainingUser user.User
err = db.Model(s).Related(&remainingUser, "Users").Error
if remainingUser.Username == username {
// if the remaining user is the one to be deleted
return fmt.Errorf("cannot delete last user from scenario without deleting scenario itself, doing nothing")
} else {
// the remaining user is NOT the one to be deleted
// that means the user to be deleted is not associated with the scenario
return gorm.ErrRecordNotFound
}
} }
return nil return nil

View file

@ -1,115 +1,490 @@
package scenario package scenario
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"net/http" "os"
"net/http/httptest"
"testing" "testing"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
) )
// Test /scenarios endpoints var router *gin.Engine
func TestScenarioEndpoints(t *testing.T) { var db *gorm.DB
var myScenarios = []common.ScenarioResponse{common.ScenarioA_response, common.ScenarioB_response} func TestMain(m *testing.M) {
var msgScenarios = common.ResponseMsgScenarios{Scenarios: myScenarios}
var msgScenario = common.ResponseMsgScenario{Scenario: common.ScenarioC_response}
var msgScenarioUpdated = common.ResponseMsgScenario{Scenario: common.ScenarioCUpdated_response}
db := common.DummyInitDB() db = common.DummyInitDB()
defer db.Close() defer db.Close()
common.DummyPopulateDB(db)
router := gin.Default() router = gin.Default()
api := router.Group("/api") api := router.Group("/api")
// All endpoints require authentication except when someone wants to
// login (POST /authenticate)
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
RegisterScenarioEndpoints(api.Group("/scenarios")) RegisterScenarioEndpoints(api.Group("/scenarios"))
credjson, _ := json.Marshal(common.CredUser) os.Exit(m.Run())
}
token := common.AuthenticateForTest(t, router, "/api/authenticate",
"POST", credjson, 200) func TestAddScenario(t *testing.T) {
// test GET scenarios/ common.DropTables(db)
err := common.NewTestEndpoint(router, token, "/api/scenarios", common.MigrateModels(db)
"GET", nil, 200, msgScenarios) common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
assert.NoError(t, err)
// authenticate as normal user
// test POST scenarios/ token, err := common.NewAuthenticateForTest(router,
err = common.NewTestEndpoint(router, token, "/api/scenarios", "/api/authenticate", "POST", common.UserACredentials)
"POST", msgScenario, 200, common.MsgOK) assert.NoError(t, err)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
// test GET scenarios/:ScenarioID newScenario := common.Request{
err = common.NewTestEndpoint(router, token, "/api/scenarios/3", Name: common.ScenarioA.Name,
"GET", nil, 200, msgScenario) Running: common.ScenarioA.Running,
assert.NoError(t, err) StartParameters: common.ScenarioA.StartParameters,
}
// test PUT scenarios/:ScenarioID code, resp, err := common.NewTestEndpoint(router, token,
err = common.NewTestEndpoint(router, token, "/api/scenarios/3", "/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
"PUT", msgScenarioUpdated, 200, common.MsgOK) assert.NoError(t, err)
assert.NoError(t, err) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
err = common.NewTestEndpoint(router, token, "/api/scenarios/3",
"GET", nil, 200, msgScenarioUpdated) // Compare POST's response with the newScenario
assert.NoError(t, err) err = common.CompareResponse(resp, common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
// test DELETE scenarios/:ScenarioID
err = common.NewTestEndpoint(router, token, "/api/scenarios/3", // Read newScenario's ID from the response
"DELETE", nil, 200, common.MsgOK) newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, "/api/scenarios", "GET",
nil, 200, msgScenarios) // Get the newScenario
assert.NoError(t, err) code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v", newScenarioID), "GET", nil)
// test GET scenarios/:ScenarioID/users assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
"/api/scenarios/1/users", "GET", nil,
200, common.KeyModels{"users": []common.User{common.UserA, common.UserB}}) // Compare GET's response with the newScenario
assert.NoError(t, err) err = common.CompareResponse(resp, common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
// test DELETE scenarios/:ScenarioID/user
err = common.NewTestEndpoint(router, token, // try to POST a malformed scenario
"/api/scenarios/1/user?username=User_B", "DELETE", nil, 200, common.MsgOK) // Required field StartParameters is missing
assert.NoError(t, err) malformedNewScenario := common.Request{
err = common.NewTestEndpoint(router, token, Username: "thisisnotneeded",
"/api/scenarios/1/users", "GET", nil, }
200, common.KeyModels{"users": []common.User{common.UserA}}) // this should NOT work and return a unprocessable entity 442 status code
assert.NoError(t, err) code, resp, err = common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": malformedNewScenario})
// test PUT scenarios/:ScenarioID/user assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
"/api/scenarios/1/user?username=User_B", "PUT", nil, 200, common.MsgOK) }
assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, func TestUpdateScenario(t *testing.T) {
"/api/scenarios/1/users", "GET", nil,
200, common.KeyModels{"users": []common.User{common.UserA, common.UserB}}) common.DropTables(db)
assert.NoError(t, err) common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// test DELETE scenarios/:ScenarioID/user for logged in user User_A
err = common.NewTestEndpoint(router, token, // authenticate as normal user
"/api/scenarios/1/user?username=User_A", "DELETE", nil, 200, common.MsgOK) token, err := common.NewAuthenticateForTest(router,
assert.NoError(t, err) "/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test if deletion of user from scenario has worked
w2 := httptest.NewRecorder() // test POST scenarios/ $newScenario
req2, _ := http.NewRequest("GET", "/api/scenarios/1/users", nil) newScenario := common.Request{
req2.Header.Add("Authorization", "Bearer "+token) Name: common.ScenarioA.Name,
router.ServeHTTP(w2, req2) Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
assert.Equal(t, 422, w2.Code) }
fmt.Println(w2.Body.String()) code, resp, err := common.NewTestEndpoint(router, token,
assert.Equal(t, "\"Access denied (for scenario ID).\"", w2.Body.String()) "/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
// TODO add tests for other return codes assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newScenario
err = common.CompareResponse(resp, common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
// Read newScenario's ID from the response
newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err)
updatedScenario := common.Request{
Name: "Updated name",
Running: !common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v", newScenarioID), "PUT", common.KeyModels{"scenario": updatedScenario})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedScenario
err = common.CompareResponse(resp, common.KeyModels{"scenario": updatedScenario})
assert.NoError(t, err)
// Get the updatedScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the newScenario
err = common.CompareResponse(resp, common.KeyModels{"scenario": updatedScenario})
assert.NoError(t, err)
// try to update a scenario that does not exist (should return not found 404 status code)
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v", newScenarioID+1), "PUT", common.KeyModels{"scenario": updatedScenario})
assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
}
func TestGetAllScenariosAsAdmin(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as admin
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.AdminCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response for admin
initialNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
// authenticate as normal userB
token, err = common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserBCredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenarioB
newScenarioB := common.Request{
Name: common.ScenarioB.Name,
Running: common.ScenarioB.Running,
StartParameters: common.ScenarioB.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenarioB})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenarioA
newScenarioA := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err = common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenarioA})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as admin
token, err = common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.AdminCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response again
finalNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber+2)
}
func TestGetAllScenariosAsUser(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as normal userB
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserBCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response for userB
initialNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
// test POST scenarios/ $newScenarioB
newScenarioB := common.Request{
Name: common.ScenarioB.Name,
Running: common.ScenarioB.Running,
StartParameters: common.ScenarioB.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenarioB})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenarioA
newScenarioA := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err = common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenarioA})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userB
token, err = common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserBCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response again
finalNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber+1)
}
func TestDeleteScenario(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as normal user
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
newScenario := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newScenario's ID from the response
newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err)
// Count the number of all the scenarios returned for userA
initialNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
// Delete the added newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v", newScenarioID), "DELETE", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with the newScenario
err = common.CompareResponse(resp, common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
// Again count the number of all the users returned
finalNumber, err := common.LengthOfResponse(router, token,
"/api/scenarios", "GET", nil)
assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber-1)
}
func TestAddUserToScenario(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as normal user
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
newScenario := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newScenario's ID from the response
newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err)
// Count the number of all the users returned for newScenario
initialNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, initialNumber, 1)
// add userB to newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_B", newScenarioID), "PUT", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare resp to userB
err = common.CompareResponse(resp, common.KeyModels{"user": common.UserB})
assert.NoError(t, err)
// Count AGAIN the number of all the users returned for newScenario
finalNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber+1)
// try to add a non-existing user to newScenario, should return a not found 404
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
}
func TestGetAllUsersOfScenario(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as normal user
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
newScenario := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newScenario's ID from the response
newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err)
// Count the number of all the users returned for newScenario
initialNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, initialNumber, 1)
// add userB to newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_B", newScenarioID), "PUT", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Count AGAIN the number of all the users returned for newScenario
finalNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, finalNumber, initialNumber+1)
}
func TestRemoveUserFromScenario(t *testing.T) {
common.DropTables(db)
common.MigrateModels(db)
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
// authenticate as normal user
token, err := common.NewAuthenticateForTest(router,
"/api/authenticate", "POST", common.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
newScenario := common.Request{
Name: common.ScenarioA.Name,
Running: common.ScenarioA.Running,
StartParameters: common.ScenarioA.StartParameters,
}
code, resp, err := common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newScenario's ID from the response
newScenarioID, err := common.GetResponseID(resp)
assert.NoError(t, err)
// add userB to newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_B", newScenarioID), "PUT", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Count the number of all the users returned for newScenario
initialNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, 2, initialNumber)
// remove userB from newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_B", newScenarioID), "DELETE", nil)
assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with UserB
err = common.CompareResponse(resp, common.KeyModels{"user": common.UserB})
assert.NoError(t, err)
// Count AGAIN the number of all the users returned for newScenario
finalNumber, err := common.LengthOfResponse(router, token,
fmt.Sprintf("/api/scenarios/%v/users", newScenarioID), "GET", nil)
assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber)
// Try to remove userA from new scenario
// This should fail since User_A is the last user of newScenario
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_A", newScenarioID), "DELETE", nil)
assert.NoError(t, err)
assert.Equalf(t, 500, code, "Response body: \n%v\n", resp)
// Try to remove a user that does not exist in DB
// This should fail with not found 404 status code
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "DELETE", nil)
assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// Try to remove an admin user that is not explicitly a user of the scenario
// This should fail with not found 404 status code
code, resp, err = common.NewTestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_0", newScenarioID), "DELETE", nil)
assert.NoError(t, err)
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
} }

View file

@ -0,0 +1,65 @@
package scenario
import (
"github.com/jinzhu/gorm/dialects/postgres"
"gopkg.in/go-playground/validator.v9"
)
var validate *validator.Validate
type validNewScenario struct {
Name string `form:"Name" validate:"required"`
Running bool `form:"Running" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
}
type validUpdatedScenario struct {
Name string `form:"Name" validate:"omitempty"`
Running bool `form:"Running" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
}
type addScenarioRequest struct {
validNewScenario `json:"scenario"`
}
type updateScenarioRequest struct {
validUpdatedScenario `json:"scenario"`
}
func (r *addScenarioRequest) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *validUpdatedScenario) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *addScenarioRequest) createScenario() Scenario {
var s Scenario
s.Name = r.Name
s.Running = r.Running
s.StartParameters = r.StartParameters
return s
}
func (r *updateScenarioRequest) updatedScenario(oldScenario Scenario) (Scenario, error) {
// Use the old Scenario as a basis for the updated Scenario `s`
s := oldScenario
if r.Name != "" {
s.Name = r.Name
}
s.Running = r.Running
// TODO check for empty start parameters?
s.StartParameters = r.StartParameters
return s, nil
}