- 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

@ -9,7 +9,6 @@ type Request struct {
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 {
// 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") 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
}