From b1e413c3fea96f741bd854c4892db05e28e4d526 Mon Sep 17 00:00:00 2001 From: Jure Skelin Date: Fri, 13 Dec 2024 15:14:36 +0100 Subject: [PATCH] feat: add deleteAll for segments (monaco purge) --- pkg/delete/delete.go | 9 ++++ pkg/delete/delete_test.go | 21 +++++++++ pkg/delete/internal/segment/delete.go | 51 +++++++++++++++++----- pkg/delete/internal/segment/delete_test.go | 26 +++++++++++ 4 files changed, 95 insertions(+), 12 deletions(-) diff --git a/pkg/delete/delete.go b/pkg/delete/delete.go index 56757c8aa..e4f18fa7d 100644 --- a/pkg/delete/delete.go +++ b/pkg/delete/delete.go @@ -165,6 +165,15 @@ func All(ctx context.Context, clients client.ClientSet, apis api.APIs) error { } } + if featureflags.Temporary[featureflags.Segments].Enabled() { + if clients.SegmentClient == nil { + log.Warn("Skipped deletion of %s configurations as appropriate client was unavailable.", config.SegmentID) + } else if err := segment.DeleteAll(ctx, clients.SegmentClient); err != nil { + log.Error("Failed to delete all %s configurations: %v", config.SegmentID, err) + errCount++ + } + } + if errCount > 0 { return fmt.Errorf("failed to delete all configurations for %d types", errCount) } diff --git a/pkg/delete/delete_test.go b/pkg/delete/delete_test.go index 3e54a84af..662518754 100644 --- a/pkg/delete/delete_test.go +++ b/pkg/delete/delete_test.go @@ -1228,3 +1228,24 @@ func TestDelete_Segments(t *testing.T) { assert.NoError(t, err) }) } + +func TestDeleteAll_Segments(t *testing.T) { + t.Run("simple case", func(t *testing.T) { + t.Setenv(featureflags.Temporary[featureflags.Segments].EnvName(), "true") + + c := client.NewMockSegmentClient(gomock.NewController(t)) + c.EXPECT().List(gomock.Any()).Return(grailfiltersegments.Response{StatusCode: http.StatusOK, Data: []byte(`[{"uid": "uid_1"},{"uid": "uid_2"},{"uid": "uid_3"}]`)}, nil).Times(1) + c.EXPECT().Delete(gomock.Any(), gomock.Any()).Times(3) + + err := delete.All(context.TODO(), client.ClientSet{SegmentClient: c}, api.APIs{}) + assert.NoError(t, err) + }) + + t.Run("FF is turned off", func(t *testing.T) { + c := client.NewMockSegmentClient(gomock.NewController(t)) + // no calls to client + + err := delete.All(context.TODO(), client.ClientSet{SegmentClient: c}, api.APIs{}) + assert.NoError(t, err) + }) +} diff --git a/pkg/delete/internal/segment/delete.go b/pkg/delete/internal/segment/delete.go index 4e7747689..92cd68513 100644 --- a/pkg/delete/internal/segment/delete.go +++ b/pkg/delete/internal/segment/delete.go @@ -79,28 +79,20 @@ func deleteSingle(ctx context.Context, c client, dp pointer.DeletePointer) error } func findEntryWithExternalID(ctx context.Context, c client, dp pointer.DeletePointer) (string, error) { - listResp, err := c.List(ctx) + items, err := list(c, ctx) if err != nil { return "", err } - var items []struct { - Uid string `json:"uid"` - ExternalId string `json:"externalId"` - } - if err = json.Unmarshal(listResp.Data, &items); err != nil { - return "", fmt.Errorf("problem with reading recieved data: %w", err) - } - extID, err := idutils.GenerateExternalIDForDocument(dp.AsCoordinate()) if err != nil { return "", fmt.Errorf("unable to generate externalID: %w", err) } var foundUid []string - for _, item := range items { - if item.ExternalId == extID { - foundUid = append(foundUid, item.Uid) + for _, i := range items { + if i.ExternalId == extID { + foundUid = append(foundUid, i.Uid) } } @@ -122,3 +114,38 @@ func isAPIErrorStatusNotFound(err error) bool { return apiErr.StatusCode == http.StatusNotFound } + +func DeleteAll(ctx context.Context, c client) error { + items, err := list(c, ctx) + if err != nil { + return err + } + + var retErr error + for _, i := range items { + err := deleteSingle(ctx, c, pointer.DeletePointer{Type: string(config.SegmentID), OriginObjectId: i.Uid}) + if err != nil { + retErr = errors.Join(retErr, err) + } + } + return retErr +} + +type items []struct { + Uid string `json:"uid"` + ExternalId string `json:"externalId"` +} + +func list(c client, ctx context.Context) (items, error) { + listResp, err := c.List(ctx) + if err != nil { + return nil, err + } + + var items items + if err = json.Unmarshal(listResp.Data, &items); err != nil { + return nil, fmt.Errorf("problem with reading recieved data: %w", err) + } + + return items, nil +} diff --git a/pkg/delete/internal/segment/delete_test.go b/pkg/delete/internal/segment/delete_test.go index ed26ab4ff..ba049cae6 100644 --- a/pkg/delete/internal/segment/delete_test.go +++ b/pkg/delete/internal/segment/delete_test.go @@ -141,3 +141,29 @@ func TestDelete(t *testing.T) { assert.Error(t, err) }) } + +func TestDeleteAll(t *testing.T) { + t.Run("simple case", func(t *testing.T) { + c := client.NewMockSegmentClient(gomock.NewController(t)) + c.EXPECT().List(gomock.Any()).Times(1). + Return(libSegment.Response{Data: []byte(`[{"uid": "uid_1"},{"uid": "uid_2"},{"uid": "uid_3"}]`)}, nil) + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_1")).Times(1) + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_2")).Times(1) + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_3")).Times(1) + + err := segment.DeleteAll(context.TODO(), c) + assert.NoError(t, err) + }) + + t.Run("error during delete - continue to delete, an error", func(t *testing.T) { + c := client.NewMockSegmentClient(gomock.NewController(t)) + c.EXPECT().List(gomock.Any()).Times(1). + Return(libSegment.Response{Data: []byte(`[{"uid": "uid_1"},{"uid": "uid_2"},{"uid": "uid_3"}]`)}, nil) + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_1")).Times(1) + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_2")).Times(1).Return(libAPI.Response{}, libAPI.APIError{StatusCode: http.StatusInternalServerError}) // the error can be any kind except 404 + c.EXPECT().Delete(gomock.Any(), gomock.Eq("uid_3")).Times(1) + + err := segment.DeleteAll(context.TODO(), c) + assert.Error(t, err) + }) +}