github.com/grafana/pyroscope@v1.18.0/pkg/compactor/job_test.go (about) 1 // SPDX-License-Identifier: AGPL-3.0-only 2 // Provenance-includes-location: https://github.com/grafana/mimir/blob/main/pkg/compactor/job_test.go 3 // Provenance-includes-license: Apache-2.0 4 // Provenance-includes-copyright: The Cortex Authors. 5 6 package compactor 7 8 import ( 9 "context" 10 "path" 11 "testing" 12 "time" 13 14 "github.com/oklog/ulid/v2" 15 "github.com/pkg/errors" 16 "github.com/prometheus/prometheus/model/labels" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 "github.com/thanos-io/objstore" 20 21 "github.com/grafana/pyroscope/pkg/phlaredb/block" 22 "github.com/grafana/pyroscope/pkg/test/mocks/mockobjstore" 23 ) 24 25 func TestJob_MinCompactionLevel(t *testing.T) { 26 job := NewJob("user-1", "group-1", labels.EmptyLabels(), 0, true, 2, 0, "shard-1") 27 require.NoError(t, job.AppendMeta(&block.Meta{ULID: ulid.MustNew(1, nil), Compaction: block.BlockMetaCompaction{Level: 2}})) 28 assert.Equal(t, 2, job.MinCompactionLevel()) 29 30 require.NoError(t, job.AppendMeta(&block.Meta{ULID: ulid.MustNew(2, nil), Compaction: block.BlockMetaCompaction{Level: 3}})) 31 assert.Equal(t, 2, job.MinCompactionLevel()) 32 33 require.NoError(t, job.AppendMeta(&block.Meta{ULID: ulid.MustNew(3, nil), Compaction: block.BlockMetaCompaction{Level: 1}})) 34 assert.Equal(t, 1, job.MinCompactionLevel()) 35 } 36 37 func TestJobWaitPeriodElapsed(t *testing.T) { 38 type jobBlock struct { 39 meta *block.Meta 40 attrs objstore.ObjectAttributes 41 attrsErr error 42 } 43 44 // Blocks with compaction level 1. 45 meta1 := &block.Meta{ULID: ulid.MustNew(1, nil), Compaction: block.BlockMetaCompaction{Level: 1}} 46 meta2 := &block.Meta{ULID: ulid.MustNew(2, nil), Compaction: block.BlockMetaCompaction{Level: 1}} 47 48 // Blocks with compaction level 2. 49 meta3 := &block.Meta{ULID: ulid.MustNew(3, nil), Compaction: block.BlockMetaCompaction{Level: 2}} 50 meta4 := &block.Meta{ULID: ulid.MustNew(4, nil), Compaction: block.BlockMetaCompaction{Level: 2}} 51 52 tests := map[string]struct { 53 waitPeriod time.Duration 54 jobBlocks []jobBlock 55 expectedElapsed bool 56 expectedMeta *block.Meta 57 expectedErr string 58 }{ 59 "wait period disabled": { 60 waitPeriod: 0, 61 jobBlocks: []jobBlock{ 62 {meta: meta1, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-20 * time.Minute)}}, 63 {meta: meta2, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-5 * time.Minute)}}, 64 }, 65 expectedElapsed: true, 66 expectedMeta: nil, 67 }, 68 "blocks uploaded since more than the wait period": { 69 waitPeriod: 10 * time.Minute, 70 jobBlocks: []jobBlock{ 71 {meta: meta1, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-20 * time.Minute)}}, 72 {meta: meta2, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-25 * time.Minute)}}, 73 }, 74 expectedElapsed: true, 75 expectedMeta: nil, 76 }, 77 "blocks uploaded since less than the wait period": { 78 waitPeriod: 10 * time.Minute, 79 jobBlocks: []jobBlock{ 80 {meta: meta1, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-20 * time.Minute)}}, 81 {meta: meta2, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-5 * time.Minute)}}, 82 }, 83 expectedElapsed: false, 84 expectedMeta: meta2, 85 }, 86 "blocks uploaded since less than the wait period but their compaction level is > 1": { 87 waitPeriod: 10 * time.Minute, 88 jobBlocks: []jobBlock{ 89 {meta: meta3, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-4 * time.Minute)}}, 90 {meta: meta4, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-5 * time.Minute)}}, 91 }, 92 expectedElapsed: true, 93 expectedMeta: nil, 94 }, 95 "an error occurred while checking the blocks upload timestamp": { 96 waitPeriod: 10 * time.Minute, 97 jobBlocks: []jobBlock{ 98 // This block has been uploaded since more than the wait period. 99 {meta: meta1, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-20 * time.Minute)}}, 100 101 // This block has been uploaded since less than the wait period, but we failed getting its attributes. 102 {meta: meta2, attrs: objstore.ObjectAttributes{LastModified: time.Now().Add(-5 * time.Minute)}, attrsErr: errors.New("mocked error")}, 103 }, 104 expectedErr: "mocked error", 105 expectedMeta: meta2, 106 }, 107 } 108 109 for testName, testData := range tests { 110 t.Run(testName, func(t *testing.T) { 111 job := NewJob("user-1", "group-1", labels.EmptyLabels(), 0, true, 2, 0, "shard-1") 112 for _, b := range testData.jobBlocks { 113 require.NoError(t, job.AppendMeta(b.meta)) 114 } 115 116 userBucket := &mockobjstore.MockBucket{} 117 for _, b := range testData.jobBlocks { 118 userBucket.MockAttributes(path.Join(b.meta.ULID.String(), block.MetaFilename), b.attrs, b.attrsErr) 119 } 120 121 elapsed, meta, err := jobWaitPeriodElapsed(context.Background(), job, testData.waitPeriod, userBucket) 122 if testData.expectedErr != "" { 123 require.Error(t, err) 124 assert.ErrorContains(t, err, testData.expectedErr) 125 assert.False(t, elapsed) 126 assert.Equal(t, testData.expectedMeta, meta) 127 } else { 128 require.NoError(t, err) 129 assert.Equal(t, testData.expectedElapsed, elapsed) 130 assert.Equal(t, testData.expectedMeta, meta) 131 } 132 }) 133 } 134 }