Skip to content

Commit

Permalink
notification: add api to redelivery a commit status delivery
Browse files Browse the repository at this point in the history
add an api to redelivery a commit status delivery by project id and commit status delivery id.
  • Loading branch information
alessandro-sorint committed Jan 8, 2024
1 parent 1ac1c71 commit 6cd419c
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 6 deletions.
49 changes: 49 additions & 0 deletions internal/services/notification/action/commitstatusdelivery.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/sorintlab/errors"

"agola.io/agola/internal/sqlg/sql"
"agola.io/agola/internal/util"
"agola.io/agola/services/notification/types"
)

Expand Down Expand Up @@ -72,3 +73,51 @@ func (h *ActionHandler) GetProjectCommitStatusDeliveries(ctx context.Context, re
HasMore: hasMore,
}, nil
}

func (h *ActionHandler) CommitStatusRedelivery(ctx context.Context, projectID string, commitStatusDeliveryID string) error {
err := h.d.Do(ctx, func(tx *sql.Tx) error {
var err error
commitStatusDelivery, err := h.d.GetCommitStatusDeliveryByID(tx, commitStatusDeliveryID)
if err != nil {
return errors.WithStack(err)
}
if commitStatusDelivery == nil {
return util.NewAPIError(util.ErrNotExist, errors.Errorf("commitStatusDelivery %q doesn't exist", commitStatusDeliveryID))
}

commitStatus, err := h.d.GetCommitStatusByID(tx, commitStatusDelivery.CommitStatusID)
if err != nil {
return errors.WithStack(err)
}
if commitStatus == nil {
return util.NewAPIError(util.ErrNotExist, errors.Errorf("commitStatus %q doesn't exist", commitStatusDelivery.CommitStatusID))
}
if commitStatus.ProjectID != projectID {
return util.NewAPIError(util.ErrNotExist, errors.Errorf("commitStatusDelivery %q doesn't belong to project %q", commitStatusDeliveryID, projectID))
}

commitStatusDeliveries, err := h.d.GetCommitStatusDeliveriesByCommitStatusID(tx, commitStatusDelivery.CommitStatusID, []types.DeliveryStatus{types.DeliveryStatusNotDelivered}, 1, types.SortDirectionDesc)
if err != nil {
return errors.WithStack(err)
}
// check if commitStatus has delivery not delivered
if len(commitStatusDeliveries) != 0 {
return util.NewAPIError(util.ErrBadRequest, errors.Errorf("the previous delivery of commit status %q hasn't already been delivered", commitStatusDelivery.CommitStatusID))
}

newCommitStatusDelivery := types.NewCommitStatusDelivery(tx)
newCommitStatusDelivery.DeliveryStatus = types.DeliveryStatusNotDelivered
newCommitStatusDelivery.CommitStatusID = commitStatusDelivery.CommitStatusID
err = h.d.InsertCommitStatusDelivery(tx, newCommitStatusDelivery)
if err != nil {
return errors.WithStack(err)
}

return nil
})
if err != nil {
return errors.WithStack(err)
}

return nil
}
36 changes: 36 additions & 0 deletions internal/services/notification/api/commitstatusdelivery.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,39 @@ func (h *CommitStatusDeliveriesHandler) do(w http.ResponseWriter, r *http.Reques

return ares.CommitStatusDeliveries, nil
}

type CommitStatusRedeliveryHandler struct {
log zerolog.Logger
ah *action.ActionHandler
}

func NewCommitStatusRedeliveryHandler(log zerolog.Logger, ah *action.ActionHandler) *CommitStatusRedeliveryHandler {
return &CommitStatusRedeliveryHandler{log: log, ah: ah}
}

func (h *CommitStatusRedeliveryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := h.do(w, r)
if util.HTTPError(w, err) {
h.log.Err(err).Send()
return
}

if err := util.HTTPResponse(w, http.StatusOK, nil); err != nil {
h.log.Err(err).Send()
}
}

func (h *CommitStatusRedeliveryHandler) do(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()

vars := mux.Vars(r)
projectID := vars["projectid"]
commitStatusDeliveryID := vars["commitstatusdeliveryid"]

err := h.ah.CommitStatusRedelivery(ctx, projectID, commitStatusDeliveryID)
if err != nil {
return errors.WithStack(err)
}

return nil
}
23 changes: 23 additions & 0 deletions internal/services/notification/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,29 @@ func (d *DB) GetProjectCommitStatusDeliveriesAfterSequenceByProjectID(tx *sql.Tx
return commitStatusDeliveries, errors.WithStack(err)
}

func (d *DB) GetCommitStatusDeliveriesByCommitStatusID(tx *sql.Tx, commitStatusID string, deliveryStatusFilter []types.DeliveryStatus, limit int, sortDirection types.SortDirection) ([]*types.CommitStatusDelivery, error) {
q := commitStatusDeliverySelect().OrderBy("sequence")
q.Where(q.E("commit_status_id", commitStatusID))

if len(deliveryStatusFilter) > 0 {
q.Where(q.In("delivery_status", sq.Flatten(deliveryStatusFilter)...))
}

switch sortDirection {
case types.SortDirectionAsc:
q.Asc()
case types.SortDirectionDesc:
q.Desc()
}

if limit > 0 {
q.Limit(limit)
}

commitStatusDeliveries, _, err := d.fetchCommitStatusDeliverys(tx, q)
return commitStatusDeliveries, errors.WithStack(err)
}

func (d *DB) DeleteCommitStatusDeliveriesByCommitStatusID(tx *sql.Tx, commitStatusID string) error {
q := sq.NewDeleteBuilder()
q.DeleteFrom("commitstatusdelivery")
Expand Down
3 changes: 3 additions & 0 deletions internal/services/notification/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (n *NotificationService) setupDefaultRouter() http.Handler {
runWebhookDeliveriesHandler := api.NewRunWebhookDeliveriesHandler(n.log, n.ah)
runWebhookReliveryHandler := api.NewRunWebhookRedeliveryHandler(n.log, n.ah)
commitStatusDeliveriesHandler := api.NewCommitStatusDeliveriesHandler(n.log, n.ah)
commitStatusReliveryHandler := api.NewCommitStatusRedeliveryHandler(n.log, n.ah)

authHandler := handlers.NewInternalAuthChecker(n.log, n.c.APIToken)

Expand All @@ -140,6 +141,8 @@ func (n *NotificationService) setupDefaultRouter() http.Handler {

apirouter.Handle("/projects/{projectid}/commitstatusdeliveries", commitStatusDeliveriesHandler).Methods("GET")

apirouter.Handle("/projects/{projectid}/commitstatusdeliveries/{commitstatusdeliveryid}/redelivery", commitStatusReliveryHandler).Methods("PUT")

mainrouter := mux.NewRouter().UseEncodedPath().SkipClean(true)
mainrouter.PathPrefix("/").Handler(router)

Expand Down
189 changes: 183 additions & 6 deletions internal/services/notification/notification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ import (
)

const (
webhookSecret = "secretkey"
webhookPayload = "payloadtest"
webhookURL = "testWebhookURL"
project01 = "project01id"
project02 = "project02id"
runWebhookDelivery01 = "runwebhookdelivery01id"
webhookSecret = "secretkey"
webhookPayload = "payloadtest"
webhookURL = "testWebhookURL"
project01 = "project01id"
project02 = "project02id"
runWebhookDelivery01 = "runwebhookdelivery01id"
commitStatusDelivery01 = "commitstatusdelivery01id"
)

// setupNotificationService don't start the notification service but just create it to manually call its methods
Expand Down Expand Up @@ -1081,3 +1082,179 @@ func deliveryStatusInSlice(deliveryStatuses []types.DeliveryStatus, deliveryStat
}
return false
}

func TestProjectCommitStatusRedelivery(t *testing.T) {
t.Parallel()

t.Run("test project commit status redelivery with deliverystatus = deliveryError", func(t *testing.T) {
dir := t.TempDir()
log := testutil.NewLogger(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ns := setupNotificationService(ctx, t, log, dir)

commitStatus := createCommitStatus(t, ctx, ns, 1, project01)
commitStatusDelivery := createCommitStatusDelivery(t, ctx, ns, commitStatus.ID, types.DeliveryStatusDeliveryError)

t.Logf("starting ns")

cs := setupStubCommitStatusUpdater()
ns.u = cs

err := ns.ah.CommitStatusRedelivery(ctx, commitStatus.ProjectID, commitStatusDelivery.ID)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}

if err := ns.commitStatusDeliveriesHandler(ctx); err != nil {
t.Fatalf("unexpected err: %v", err)
}

res, err := ns.ah.GetProjectCommitStatusDeliveries(ctx, &action.GetProjectCommitStatusDeliveriesRequest{ProjectID: project01, SortDirection: types.SortDirectionAsc})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if len(res.CommitStatusDeliveries) != 2 {
t.Fatalf("expected 2 CommitStatusDeliveries got: %d", len(res.CommitStatusDeliveries))
}
if res.CommitStatusDeliveries[0].DeliveryStatus != types.DeliveryStatusDeliveryError {
t.Fatalf("expected %q DeliveryStatus got: %q", types.DeliveryStatusDeliveryError, res.CommitStatusDeliveries[0].DeliveryStatus)
}
if res.CommitStatusDeliveries[1].DeliveryStatus != types.DeliveryStatusDelivered {
t.Fatalf("expected %q DeliveryStatus got: %q", types.DeliveryStatusDelivered, res.CommitStatusDeliveries[1].DeliveryStatus)
}
})

t.Run("test project commit status redelivery with deliverystatus = delivered", func(t *testing.T) {
dir := t.TempDir()
log := testutil.NewLogger(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ns := setupNotificationService(ctx, t, log, dir)

commitStatus := createCommitStatus(t, ctx, ns, 1, project01)
commitStatusDelivery := createCommitStatusDelivery(t, ctx, ns, commitStatus.ID, types.DeliveryStatusDelivered)

t.Logf("starting ns")

cs := setupStubCommitStatusUpdater()
ns.u = cs

err := ns.ah.CommitStatusRedelivery(ctx, commitStatus.ProjectID, commitStatusDelivery.ID)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}

if err := ns.commitStatusDeliveriesHandler(ctx); err != nil {
t.Fatalf("unexpected err: %v", err)
}

res, err := ns.ah.GetProjectCommitStatusDeliveries(ctx, &action.GetProjectCommitStatusDeliveriesRequest{ProjectID: project01, SortDirection: types.SortDirectionAsc})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if len(res.CommitStatusDeliveries) != 2 {
t.Fatalf("expected 2 CommitStatusDeliveries got: %d", len(res.CommitStatusDeliveries))
}
if res.CommitStatusDeliveries[0].DeliveryStatus != types.DeliveryStatusDelivered {
t.Fatalf("expected %q DeliveryStatus got: %q", types.DeliveryStatusDelivered, res.CommitStatusDeliveries[0].DeliveryStatus)
}
if res.CommitStatusDeliveries[1].DeliveryStatus != types.DeliveryStatusDelivered {
t.Fatalf("expected %q DeliveryStatus got: %q", types.DeliveryStatusDelivered, res.CommitStatusDeliveries[1].DeliveryStatus)
}
})

t.Run("test redelivery not existing project commit status delivery", func(t *testing.T) {
dir := t.TempDir()
log := testutil.NewLogger(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ns := setupNotificationService(ctx, t, log, dir)

commitStatus := createCommitStatus(t, ctx, ns, 1, project01)

expectedErr := util.NewAPIError(util.ErrNotExist, errors.Errorf("commitStatusDelivery %q doesn't exist", commitStatusDelivery01))
err := ns.ah.CommitStatusRedelivery(ctx, commitStatus.ProjectID, commitStatusDelivery01)
if err == nil {
t.Fatalf("expected error %v, got nil err", expectedErr)
}
if err.Error() != expectedErr.Error() {
t.Fatalf("expected err %v, got err: %v", expectedErr, err)
}
})

t.Run("test project commit status redelivery with projectID that belong to another project", func(t *testing.T) {
dir := t.TempDir()
log := testutil.NewLogger(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ns := setupNotificationService(ctx, t, log, dir)

commitStatus := createCommitStatus(t, ctx, ns, 1, project01)
commitStatusDelivery := createCommitStatusDelivery(t, ctx, ns, commitStatus.ID, types.DeliveryStatusDelivered)

commitStatus = createCommitStatus(t, ctx, ns, 1, project02)
createCommitStatusDelivery(t, ctx, ns, commitStatus.ID, types.DeliveryStatusDelivered)

expectedErr := util.NewAPIError(util.ErrNotExist, errors.Errorf("commitStatusDelivery %q doesn't belong to project %q", commitStatusDelivery.ID, project02))

err := ns.ah.CommitStatusRedelivery(ctx, project02, commitStatusDelivery.ID)
if err == nil {
t.Fatalf("expected error %v, got nil err", expectedErr)
}
if err.Error() != expectedErr.Error() {
t.Fatalf("expected err %v, got err: %v", expectedErr, err)
}
})

t.Run("test project commit status redelivery with the last delivery that hasn't been delivered", func(t *testing.T) {
dir := t.TempDir()
log := testutil.NewLogger(t)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ns := setupNotificationService(ctx, t, log, dir)

commitStatus := createCommitStatus(t, ctx, ns, 1, project01)
commitStatusDelivery := createCommitStatusDelivery(t, ctx, ns, commitStatus.ID, types.DeliveryStatusNotDelivered)

t.Logf("starting ns")

cs := setupStubCommitStatusUpdater()
ns.u = cs

expectedErr := util.NewAPIError(util.ErrBadRequest, errors.Errorf("the previous delivery of commit status %q hasn't already been delivered", commitStatusDelivery.CommitStatusID))

err := ns.ah.CommitStatusRedelivery(ctx, commitStatus.ProjectID, commitStatusDelivery.ID)
if err == nil {
t.Fatalf("expected error %v, got nil err", expectedErr)
}
if err.Error() != expectedErr.Error() {
t.Fatalf("expected err %v, got err: %v", expectedErr, err)
}

if err := ns.commitStatusDeliveriesHandler(ctx); err != nil {
t.Fatalf("unexpected err: %v", err)
}

res, err := ns.ah.GetProjectCommitStatusDeliveries(ctx, &action.GetProjectCommitStatusDeliveriesRequest{ProjectID: project01, SortDirection: types.SortDirectionAsc})
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if len(res.CommitStatusDeliveries) != 1 {
t.Fatalf("expected 1 CommitStatusDeliveries got: %d", len(res.CommitStatusDeliveries))
}
if res.CommitStatusDeliveries[0].DeliveryStatus != types.DeliveryStatusDelivered {
t.Fatalf("expected %q DeliveryStatus got: %q", types.DeliveryStatusDelivered, res.CommitStatusDeliveries[0].DeliveryStatus)
}
})
}
5 changes: 5 additions & 0 deletions services/notification/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,8 @@ func (c *Client) GetProjectCommitStatusDeliveries(ctx context.Context, projectID
resp, err := c.GetParsedResponse(ctx, "GET", fmt.Sprintf("/projects/%s/commitstatusdeliveries", projectID), q, common.JSONContent, nil, &commitStatusDeliveries)
return commitStatusDeliveries, resp, errors.WithStack(err)
}

func (c *Client) CommitStatusRedelivery(ctx context.Context, projectID, commitStatusDeliveryID string) (*Response, error) {
resp, err := c.GetResponse(ctx, "PUT", fmt.Sprintf("/projects/%s/commitstatusdeliveries/%s/redelivery", projectID, commitStatusDeliveryID), nil, -1, common.JSONContent, nil)
return resp, errors.WithStack(err)
}

0 comments on commit 6cd419c

Please sign in to comment.