- 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 Request struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Mail string `json:"mail,omitempty"`
Role string `json:"role,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Mail string `json:"mail,omitempty"`
Role string `json:"role,omitempty"`
Name string `json:"name,omitempty"`
Running bool `json:"running,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`

View file

@ -2,13 +2,6 @@ package common
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 {
ID uint `json:"id"`
Name string `json:"name"`
@ -80,14 +73,6 @@ type ResponseMsg struct {
Message string `json:"message"`
}
type ResponseMsgScenarios struct {
Scenarios []ScenarioResponse `json:"scenarios"`
}
type ResponseMsgScenario struct {
Scenario ScenarioResponse `json:"scenario"`
}
type ResponseMsgSimulationModels struct {
SimulationModels []SimulationModelResponse `json:"models"`
}

View file

@ -4,37 +4,6 @@ import (
"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
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 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_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

View file

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

View file

@ -2,9 +2,9 @@ package scenario
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
"github.com/jinzhu/gorm"
)
type Scenario struct {
@ -15,7 +15,7 @@ func (s *Scenario) ByID(id uint) error {
db := common.GetDB()
err := db.Find(s, id).Error
if err != nil {
return fmt.Errorf("scenario with id=%v does not exist", id)
return err
}
return nil
}
@ -33,9 +33,15 @@ func (s *Scenario) save() error {
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()
err := db.Model(s).Update(modifiedScenario).Error
err := db.Model(s).Update(updatedScenario).Error
return err
}
@ -69,7 +75,17 @@ func (s *Scenario) deleteUser(username string) error {
return err
}
} 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

View file

@ -1,115 +1,490 @@
package scenario
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"os"
"testing"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
)
// Test /scenarios endpoints
func TestScenarioEndpoints(t *testing.T) {
var router *gin.Engine
var db *gorm.DB
var myScenarios = []common.ScenarioResponse{common.ScenarioA_response, common.ScenarioB_response}
var msgScenarios = common.ResponseMsgScenarios{Scenarios: myScenarios}
var msgScenario = common.ResponseMsgScenario{Scenario: common.ScenarioC_response}
var msgScenarioUpdated = common.ResponseMsgScenario{Scenario: common.ScenarioCUpdated_response}
func TestMain(m *testing.M) {
db := common.DummyInitDB()
db = common.DummyInitDB()
defer db.Close()
common.DummyPopulateDB(db)
router := gin.Default()
router = gin.Default()
api := router.Group("/api")
// All endpoints require authentication except when someone wants to
// login (POST /authenticate)
user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true))
RegisterScenarioEndpoints(api.Group("/scenarios"))
credjson, _ := json.Marshal(common.CredUser)
token := common.AuthenticateForTest(t, router, "/api/authenticate",
"POST", credjson, 200)
// test GET scenarios/
err := common.NewTestEndpoint(router, token, "/api/scenarios",
"GET", nil, 200, msgScenarios)
assert.NoError(t, err)
// test POST scenarios/
err = common.NewTestEndpoint(router, token, "/api/scenarios",
"POST", msgScenario, 200, common.MsgOK)
assert.NoError(t, err)
// test GET scenarios/:ScenarioID
err = common.NewTestEndpoint(router, token, "/api/scenarios/3",
"GET", nil, 200, msgScenario)
assert.NoError(t, err)
// test PUT scenarios/:ScenarioID
err = common.NewTestEndpoint(router, token, "/api/scenarios/3",
"PUT", msgScenarioUpdated, 200, common.MsgOK)
assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, "/api/scenarios/3",
"GET", nil, 200, msgScenarioUpdated)
assert.NoError(t, err)
// test DELETE scenarios/:ScenarioID
err = common.NewTestEndpoint(router, token, "/api/scenarios/3",
"DELETE", nil, 200, common.MsgOK)
assert.NoError(t, err)
err = common.NewTestEndpoint(router, token, "/api/scenarios", "GET",
nil, 200, msgScenarios)
assert.NoError(t, err)
// test GET scenarios/:ScenarioID/users
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/users", "GET", nil,
200, common.KeyModels{"users": []common.User{common.UserA, common.UserB}})
assert.NoError(t, err)
// test DELETE scenarios/:ScenarioID/user
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/user?username=User_B", "DELETE", nil, 200, common.MsgOK)
assert.NoError(t, err)
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/users", "GET", nil,
200, common.KeyModels{"users": []common.User{common.UserA}})
assert.NoError(t, err)
// test PUT scenarios/:ScenarioID/user
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/user?username=User_B", "PUT", nil, 200, common.MsgOK)
assert.NoError(t, err)
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/users", "GET", nil,
200, common.KeyModels{"users": []common.User{common.UserA, common.UserB}})
assert.NoError(t, err)
// test DELETE scenarios/:ScenarioID/user for logged in user User_A
err = common.NewTestEndpoint(router, token,
"/api/scenarios/1/user?username=User_A", "DELETE", nil, 200, common.MsgOK)
assert.NoError(t, err)
// test if deletion of user from scenario has worked
w2 := httptest.NewRecorder()
req2, _ := http.NewRequest("GET", "/api/scenarios/1/users", nil)
req2.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w2, req2)
assert.Equal(t, 422, w2.Code)
fmt.Println(w2.Body.String())
assert.Equal(t, "\"Access denied (for scenario ID).\"", w2.Body.String())
// TODO add tests for other return codes
os.Exit(m.Run())
}
func TestAddScenario(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)
// 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)
// Get the newScenario
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": newScenario})
assert.NoError(t, err)
// try to POST a malformed scenario
// Required field StartParameters is missing
malformedNewScenario := common.Request{
Username: "thisisnotneeded",
}
// this should NOT work and return a unprocessable entity 442 status code
code, resp, err = common.NewTestEndpoint(router, token,
"/api/scenarios", "POST", common.KeyModels{"scenario": malformedNewScenario})
assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
}
func TestUpdateScenario(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)
// 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
}