1package deletion 2 3import ( 4 "testing" 5 "time" 6 7 "github.com/prometheus/common/model" 8 "github.com/prometheus/prometheus/pkg/labels" 9 "github.com/stretchr/testify/require" 10 11 "github.com/grafana/loki/pkg/logql" 12 "github.com/grafana/loki/pkg/storage/stores/shipper/compactor/retention" 13) 14 15func TestDeleteRequest_IsDeleted(t *testing.T) { 16 now := model.Now() 17 user1 := "user1" 18 19 lbls := `{foo="bar", fizz="buzz"}` 20 21 chunkEntry := retention.ChunkEntry{ 22 ChunkRef: retention.ChunkRef{ 23 UserID: []byte(user1), 24 From: now.Add(-3 * time.Hour), 25 Through: now.Add(-time.Hour), 26 }, 27 Labels: mustParseLabel(lbls), 28 } 29 30 type resp struct { 31 isDeleted bool 32 nonDeletedIntervals []model.Interval 33 } 34 35 for _, tc := range []struct { 36 name string 37 deleteRequest DeleteRequest 38 expectedResp resp 39 }{ 40 { 41 name: "whole chunk deleted", 42 deleteRequest: DeleteRequest{ 43 UserID: user1, 44 StartTime: now.Add(-3 * time.Hour), 45 EndTime: now.Add(-time.Hour), 46 Selectors: []string{lbls}, 47 }, 48 expectedResp: resp{ 49 isDeleted: true, 50 nonDeletedIntervals: nil, 51 }, 52 }, 53 { 54 name: "chunk deleted from beginning", 55 deleteRequest: DeleteRequest{ 56 UserID: user1, 57 StartTime: now.Add(-3 * time.Hour), 58 EndTime: now.Add(-2 * time.Hour), 59 Selectors: []string{lbls}, 60 }, 61 expectedResp: resp{ 62 isDeleted: true, 63 nonDeletedIntervals: []model.Interval{ 64 { 65 Start: now.Add(-2*time.Hour) + 1, 66 End: now.Add(-time.Hour), 67 }, 68 }, 69 }, 70 }, 71 { 72 name: "chunk deleted from end", 73 deleteRequest: DeleteRequest{ 74 UserID: user1, 75 StartTime: now.Add(-2 * time.Hour), 76 EndTime: now, 77 Selectors: []string{lbls}, 78 }, 79 expectedResp: resp{ 80 isDeleted: true, 81 nonDeletedIntervals: []model.Interval{ 82 { 83 Start: now.Add(-3 * time.Hour), 84 End: now.Add(-2*time.Hour) - 1, 85 }, 86 }, 87 }, 88 }, 89 { 90 name: "chunk deleted from end", 91 deleteRequest: DeleteRequest{ 92 UserID: user1, 93 StartTime: now.Add(-2 * time.Hour), 94 EndTime: now, 95 Selectors: []string{lbls}, 96 }, 97 expectedResp: resp{ 98 isDeleted: true, 99 nonDeletedIntervals: []model.Interval{ 100 { 101 Start: now.Add(-3 * time.Hour), 102 End: now.Add(-2*time.Hour) - 1, 103 }, 104 }, 105 }, 106 }, 107 { 108 name: "chunk deleted in the middle", 109 deleteRequest: DeleteRequest{ 110 UserID: user1, 111 StartTime: now.Add(-(2*time.Hour + 30*time.Minute)), 112 EndTime: now.Add(-(time.Hour + 30*time.Minute)), 113 Selectors: []string{lbls}, 114 }, 115 expectedResp: resp{ 116 isDeleted: true, 117 nonDeletedIntervals: []model.Interval{ 118 { 119 Start: now.Add(-3 * time.Hour), 120 End: now.Add(-(2*time.Hour + 30*time.Minute)) - 1, 121 }, 122 { 123 Start: now.Add(-(time.Hour + 30*time.Minute)) + 1, 124 End: now.Add(-time.Hour), 125 }, 126 }, 127 }, 128 }, 129 { 130 name: "delete request out of range", 131 deleteRequest: DeleteRequest{ 132 UserID: user1, 133 StartTime: now.Add(-12 * time.Hour), 134 EndTime: now.Add(-10 * time.Hour), 135 Selectors: []string{lbls}, 136 }, 137 expectedResp: resp{ 138 isDeleted: false, 139 }, 140 }, 141 { 142 name: "request not matching due to matchers", 143 deleteRequest: DeleteRequest{ 144 UserID: user1, 145 StartTime: now.Add(-3 * time.Hour), 146 EndTime: now.Add(-time.Hour), 147 Selectors: []string{`{foo1="bar"}`, `{fizz1="buzz"}`}, 148 }, 149 expectedResp: resp{ 150 isDeleted: false, 151 }, 152 }, 153 { 154 name: "request for a different user", 155 deleteRequest: DeleteRequest{ 156 UserID: "user2", 157 StartTime: now.Add(-3 * time.Hour), 158 EndTime: now.Add(-time.Hour), 159 Selectors: []string{lbls}, 160 }, 161 expectedResp: resp{ 162 isDeleted: false, 163 }, 164 }, 165 } { 166 t.Run(tc.name, func(t *testing.T) { 167 isDeleted, nonDeletedIntervals := tc.deleteRequest.IsDeleted(chunkEntry) 168 require.Equal(t, tc.expectedResp.isDeleted, isDeleted) 169 require.Equal(t, tc.expectedResp.nonDeletedIntervals, nonDeletedIntervals) 170 }) 171 } 172} 173 174func mustParseLabel(input string) labels.Labels { 175 lbls, err := logql.ParseLabels(input) 176 if err != nil { 177 panic(err) 178 } 179 180 return lbls 181} 182