From 24c4e691a784a6f1ecb227931095d1ae8998dae0 Mon Sep 17 00:00:00 2001 From: vDawgg Date: Sat, 23 Jul 2022 13:32:15 +0200 Subject: [PATCH 1/2] Checks for making reservation added. Still needs to be tested (after merging mail) --- api/reservations.go | 59 ++++++++++++++++++++++++++++++++++++ db/reservationDBInterface.go | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/api/reservations.go b/api/reservations.go index fa72e17..f423f88 100644 --- a/api/reservations.go +++ b/api/reservations.go @@ -133,6 +133,19 @@ func reservationCreateHandler() func(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } + if r.StartTime > r.EndTime { + return fiber.NewError(fiber.StatusBadRequest, "Start-date cannot be later than end-date") + } + + b, err := isAvailable(*r) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + if !b { + return fiber.NewError(fiber.StatusBadRequest, "Not enough nodes available to make reservation") + } + reservation, err := db.AddReservation(*r) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) @@ -165,6 +178,19 @@ func reservationUpdateHandler() func(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } + if r.StartTime > r.EndTime { + return fiber.NewError(fiber.StatusBadRequest, "Start-date cannot be later than end-date") + } + + b, err := isAvailable(*r) + if err != nil { + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + if !b { + return fiber.NewError(fiber.StatusBadRequest, "Not enough nodes available to make reservation") + } + reservation, err := db.EditReservation(id, *r) if err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) @@ -200,3 +226,36 @@ func reservationDeleteHandler() func(c *fiber.Ctx) error { return c.SendStatus(204) } } + +func isAvailable(reservation db.Reservation) (bool, error) { + + cluster, err := db.GetCResourceById(reservation.ClusterID) + if err != nil { + return false, err + } + + reservations, err := db.GetReservationsByClusterId(reservation.ClusterID) + if err != nil { + return false, err + } + + clusterReservations := make(map[int64]int64) //Maps startTime to nodes used + + for _, r := range reservations { + for start := reservation.StartTime; start <= reservation.EndTime; start += 86400 { + if start < r.EndTime { + clusterReservations[start] += r.Nodes + } else { + clusterReservations[start] += 0 + } + } + } + + for n := range clusterReservations { + if cluster.Nodes-n > reservation.Nodes { + return false, nil + } + } + + return true, nil +} diff --git a/db/reservationDBInterface.go b/db/reservationDBInterface.go index c95828a..4c59eb6 100644 --- a/db/reservationDBInterface.go +++ b/db/reservationDBInterface.go @@ -13,7 +13,7 @@ type Reservation struct { ID primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"` ClusterID primitive.ObjectID `bson:"clusterID" json:"clusterID"` UserID primitive.ObjectID `bson:"userID" json:"userID"` - Nodes int `bson:"nodes" json:"nodes"` + Nodes int64 `bson:"nodes" json:"nodes"` StartTime int64 `bson:"startTime" json:"startTime"` EndTime int64 `bson:"endTime" json:"endTime"` IsExpired bool `bson:"isExpired" json:"isExpired"` From d9c3cca8def43ddee404c47f4136a77b13fdba18 Mon Sep 17 00:00:00 2001 From: vDawgg Date: Sun, 24 Jul 2022 16:12:08 +0000 Subject: [PATCH 2/2] Added testing --- api/reservations.go | 8 +++++-- tests/reservations_test.go | 44 +++++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/api/reservations.go b/api/reservations.go index f4e1ecb..d9d138d 100644 --- a/api/reservations.go +++ b/api/reservations.go @@ -126,6 +126,7 @@ func reservationClusterHandler() func(c *fiber.Ctx) error { // @Produce json // @Success 201 {object} db.Reservation // @Failure 404 {object} string +// @Failure 400 {object} string // @Failure 500 {object} string // @Router /api/reservations/ [post] func reservationCreateHandler() func(c *fiber.Ctx) error { @@ -256,6 +257,9 @@ func isAvailable(reservation db.Reservation) (bool, error) { clusterReservations := make(map[int64]int64) //Maps startTime to nodes used for _, r := range reservations { + if r.ID == reservation.ID { //If reservation already exists, skip this reservation + continue + } for start := reservation.StartTime; start <= reservation.EndTime; start += 86400 { if start < r.EndTime { clusterReservations[start] += r.Nodes @@ -265,8 +269,8 @@ func isAvailable(reservation db.Reservation) (bool, error) { } } - for n := range clusterReservations { - if cluster.Nodes-n > reservation.Nodes { + for _, n := range clusterReservations { + if cluster.Nodes-n < reservation.Nodes { return false, nil } } diff --git a/tests/reservations_test.go b/tests/reservations_test.go index 5a31a71..95c9e06 100644 --- a/tests/reservations_test.go +++ b/tests/reservations_test.go @@ -43,6 +43,24 @@ func Test_reservations(t *testing.T) { createdCResource := executeTestReq[db.CResource](t, app, createOnecResourceTest, tokenStr) foosReservation := db.Reservation{ + ClusterID: createdCResource.ID, + Nodes: 5, + UserID: createdUser.ID, + StartTime: start.Unix(), + EndTime: end.Unix(), + IsExpired: false, + } + + endBeforeStartReservation := db.Reservation{ + ClusterID: createdCResource.ID, + Nodes: 5, + UserID: createdUser.ID, + StartTime: end.Unix(), + EndTime: start.Unix(), + IsExpired: false, + } + + insufficienNodesReservation := db.Reservation{ ClusterID: createdCResource.ID, Nodes: 10, UserID: createdUser.ID, @@ -52,11 +70,11 @@ func Test_reservations(t *testing.T) { } start = start.Truncate(time.Hour * 24) - end = end.Truncate(time.Hour * 72) + end = end.Truncate(time.Hour * 24) expiredReservation := db.Reservation{ ClusterID: createdCResource.ID, - Nodes: 10, + Nodes: 4, UserID: createdUser.ID, StartTime: start.Unix(), EndTime: end.Unix(), @@ -115,7 +133,7 @@ func Test_reservations(t *testing.T) { executeTestReq[db.Reservation](t, app, getOneTest, tokenStr) editedReservation := createdReservation - editedReservation.Nodes = 15 + editedReservation.Nodes = 6 editOneTest := TestReq{ description: "Edit one reservation (expect 200)", expectedCode: 200, @@ -126,6 +144,26 @@ func Test_reservations(t *testing.T) { } executeTestReq[db.Reservation](t, app, editOneTest, tokenStr) + endBeforeStartTest := TestReq{ + description: "Add one reservation where end < start", + expectedCode: 400, + route: "/api/reservations/", + method: "POST", + body: endBeforeStartReservation, + expectedData: nil, + } + _ = executeTestReq[db.Reservation](t, app, endBeforeStartTest, tokenStr) + + insufficienNodesTest := TestReq{ + description: "Add one reservation with more nodes than the cluster has available", + expectedCode: 400, + route: "/api/reservations", + method: "POST", + body: insufficienNodesReservation, + expectedData: nil, + } + _ = executeTestReq[db.Reservation](t, app, insufficienNodesTest, tokenStr) + deleteOneTest := TestReq{ description: "Delete one reservation (expect 204)", expectedCode: 204,