From d8eb67d2ae600d836e97935961a8442ef141d1a5 Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Mon, 15 Dec 2025 02:08:09 -0500 Subject: [PATCH 1/4] fix: updates for tsdb blocks handling Two small fixes: - I forgot the implementation for `*apiClientImpl.Do()` already extracts the response content from the enveloped `data` field in the response, so the wrapper struct isn't needed here. - The `compaction` section of a block has an optional `parents` field for tracking block lineage in deeper compaction levels. This slipped my mind during implementation because I was looking at the example API response on the API docs, which use a mock response with a single block that is uncompacted. I noticed these while working on tjhop/prometheus-mcp-server#77 Signed-off-by: TJ Hoplock --- api/prometheus/v1/api.go | 20 ++++++----- api/prometheus/v1/api_test.go | 66 ++++++++++++++++------------------- 2 files changed, 41 insertions(+), 45 deletions(-) diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 8e5e6a390..b48c7fef6 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -696,14 +696,8 @@ type TSDBHeadStats struct { MaxTime int `json:"maxTime"` } -// TSDBBlocksResult contains the results from querying the tsdb blocks endpoint. -type TSDBBlocksResult struct { - Status string `json:"status"` - Data TSDBBlocksData `json:"data"` -} - // TSDBBlocksData contains the metadata for the tsdb blocks. -type TSDBBlocksData struct { +type TSDBBlocksResult struct { Blocks []TSDBBlocksBlockMetadata `json:"blocks"` } @@ -724,10 +718,18 @@ type TSDBBlocksStats struct { NumChunks int `json:"numChunks"` } +// TSDBBlocksCompactionParent contains details on parent blocks for a single tsdb block. +type TSDBBlocksCompactionParent struct { + Ulid string `json:"ulid"` + MinTime int64 `json:"minTime"` + MaxTime int64 `json:"maxTime"` +} + // TSDBBlocksCompaction contains block compaction details for a single block. type TSDBBlocksCompaction struct { - Level int `json:"level"` - Sources []string `json:"sources"` + Level int `json:"level"` + Sources []string `json:"sources"` + Parents []TSDBBlocksCompactionParent `json:"parents,omitempty"` } // WalReplayStatus represents the wal replay status. diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index aa26cba8d..7a3b12f90 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -1206,48 +1206,42 @@ func TestAPIs(t *testing.T) { reqMethod: "GET", reqPath: "/api/v1/status/tsdb/blocks", inRes: map[string]interface{}{ - "status": "success", - "data": map[string]interface{}{ - "blocks": []interface{}{ - map[string]interface{}{ - "ulid": "01JZ8JKZY6XSK3PTDP9ZKRWT60", - "minTime": 1750860620060, - "maxTime": 1750867200000, - "stats": map[string]interface{}{ - "numSamples": 13701, - "numSeries": 716, - "numChunks": 716, - }, - "compaction": map[string]interface{}{ - "level": 1, - "sources": []interface{}{ - "01JZ8JKZY6XSK3PTDP9ZKRWT60", - }, + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01JZ8JKZY6XSK3PTDP9ZKRWT60", + "minTime": 1750860620060, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 13701, + "numSeries": 716, + "numChunks": 716, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01JZ8JKZY6XSK3PTDP9ZKRWT60", }, - "version": 1, }, + "version": 1, }, }, }, res: TSDBBlocksResult{ - Status: "success", - Data: TSDBBlocksData{ - Blocks: []TSDBBlocksBlockMetadata{{ - Ulid: "01JZ8JKZY6XSK3PTDP9ZKRWT60", - MinTime: 1750860620060, - MaxTime: 1750867200000, - Version: 1, - Stats: TSDBBlocksStats{ - NumSamples: 13701, - NumSeries: 716, - NumChunks: 716, - }, - Compaction: TSDBBlocksCompaction{ - Level: 1, - Sources: []string{"01JZ8JKZY6XSK3PTDP9ZKRWT60"}, - }, - }}, - }, + Blocks: []TSDBBlocksBlockMetadata{{ + Ulid: "01JZ8JKZY6XSK3PTDP9ZKRWT60", + MinTime: 1750860620060, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlocksStats{ + NumSamples: 13701, + NumSeries: 716, + NumChunks: 716, + }, + Compaction: TSDBBlocksCompaction{ + Level: 1, + Sources: []string{"01JZ8JKZY6XSK3PTDP9ZKRWT60"}, + }, + }}, }, }, From 96ed3389237142407629656a1fa1582f857bdcb5 Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Thu, 29 Jan 2026 16:50:30 -0500 Subject: [PATCH 2/4] fix(api): align tsdb blocks struct names with upstream, reduce stutter Signed-off-by: TJ Hoplock --- api/prometheus/v1/api.go | 76 +++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index b48c7fef6..7bfdd7149 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -696,40 +696,60 @@ type TSDBHeadStats struct { MaxTime int `json:"maxTime"` } -// TSDBBlocksData contains the metadata for the tsdb blocks. +// TSDBBlocksResult contains the result from querying the tsdb blocks endpoint. +// +// Note: TSDB block types are defined locally rather than importing from +// prometheus/prometheus to avoid circular dependencies and minimize the +// dependency footprint. These types match the HTTP API wire format and use +// string for ULID fields (since JSON serializes ULIDs as strings). See the +// individual type comments for links to upstream Prometheus definitions. type TSDBBlocksResult struct { - Blocks []TSDBBlocksBlockMetadata `json:"blocks"` -} - -// TSDBBlocksBlockMetadata contains the metadata for a single tsdb block. -type TSDBBlocksBlockMetadata struct { - Ulid string `json:"ulid"` - MinTime int64 `json:"minTime"` - MaxTime int64 `json:"maxTime"` - Stats TSDBBlocksStats `json:"stats"` - Compaction TSDBBlocksCompaction `json:"compaction"` - Version int `json:"version"` -} - -// TSDBBlocksStats contains block stats for a single tsdb block. -type TSDBBlocksStats struct { - NumSamples int `json:"numSamples"` - NumSeries int `json:"numSeries"` - NumChunks int `json:"numChunks"` -} - -// TSDBBlocksCompactionParent contains details on parent blocks for a single tsdb block. -type TSDBBlocksCompactionParent struct { + Blocks []TSDBBlockMeta `json:"blocks"` +} + +// TSDBBlockMeta contains the metadata for a single TSDB block. +// Counterpart to prometheus/prometheus tsdb.BlockMeta: +// https://github.com/prometheus/prometheus/blob/304dcdf6959d7a45530e9b6efa4080c5ca37dbf7/tsdb/block.go#L164 +type TSDBBlockMeta struct { + Ulid string `json:"ulid"` + MinTime int64 `json:"minTime"` + MaxTime int64 `json:"maxTime"` + Stats TSDBBlockStats `json:"stats,omitempty"` + Compaction TSDBBlockMetaCompaction `json:"compaction"` + Version int `json:"version"` +} + +// TSDBBlockStats contains block stats for a single TSDB block. +// Counterpart to prometheus/prometheus tsdb.BlockStats: +// https://github.com/prometheus/prometheus/blob/304dcdf6959d7a45530e9b6efa4080c5ca37dbf7/tsdb/block.go#L184 +type TSDBBlockStats struct { + NumSamples uint64 `json:"numSamples"` + NumFloatSamples uint64 `json:"numFloatSamples,omitempty"` + NumHistogramSamples uint64 `json:"numHistogramSamples,omitempty"` + NumSeries uint64 `json:"numSeries"` + NumChunks uint64 `json:"numChunks"` + NumTombstones uint64 `json:"numTombstones,omitempty"` +} + +// TSDBBlockDesc describes a TSDB block reference, used in compaction parent tracking. +// Counterpart to prometheus/prometheus tsdb.BlockDesc: +// https://github.com/prometheus/prometheus/blob/304dcdf6959d7a45530e9b6efa4080c5ca37dbf7/tsdb/block.go#L192 +type TSDBBlockDesc struct { Ulid string `json:"ulid"` MinTime int64 `json:"minTime"` MaxTime int64 `json:"maxTime"` } -// TSDBBlocksCompaction contains block compaction details for a single block. -type TSDBBlocksCompaction struct { - Level int `json:"level"` - Sources []string `json:"sources"` - Parents []TSDBBlocksCompactionParent `json:"parents,omitempty"` +// TSDBBlockMetaCompaction contains block compaction details for a single TSDB block. +// Counterpart to prometheus/prometheus tsdb.BlockMetaCompaction: +// https://github.com/prometheus/prometheus/blob/304dcdf6959d7a45530e9b6efa4080c5ca37dbf7/tsdb/block.go#L198 +type TSDBBlockMetaCompaction struct { + Level int `json:"level"` + Sources []string `json:"sources"` + Deletable bool `json:"deletable,omitempty"` + Parents []TSDBBlockDesc `json:"parents,omitempty"` + Failed bool `json:"failed,omitempty"` + Hints []string `json:"hints,omitempty"` } // WalReplayStatus represents the wal replay status. From 9e38b647d9ddc8b7151b206ba5c173d54644ce26 Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Thu, 29 Jan 2026 16:52:25 -0500 Subject: [PATCH 3/4] test(api): expand test coverage for tsdb blocks endpoint we've been bit by missing fields and bad parity already, so this drammatically expands test coverage for the tsdb blocks endpoint to more ocmprehensively handle optional fields, unset fields, etc etc. Signed-off-by: TJ Hoplock --- api/prometheus/v1/api_test.go | 502 +++++++++++++++++++++++++++++++++- 1 file changed, 499 insertions(+), 3 deletions(-) diff --git a/api/prometheus/v1/api_test.go b/api/prometheus/v1/api_test.go index 7a3b12f90..af9a35416 100644 --- a/api/prometheus/v1/api_test.go +++ b/api/prometheus/v1/api_test.go @@ -1201,6 +1201,20 @@ func TestAPIs(t *testing.T) { err: errors.New("some error"), }, + // Empty blocks list. + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{}, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{}, + }, + }, + + // Single uncompacted block with minimal fields. { do: doTSDBBlocks(), reqMethod: "GET", @@ -1227,17 +1241,17 @@ func TestAPIs(t *testing.T) { }, }, res: TSDBBlocksResult{ - Blocks: []TSDBBlocksBlockMetadata{{ + Blocks: []TSDBBlockMeta{{ Ulid: "01JZ8JKZY6XSK3PTDP9ZKRWT60", MinTime: 1750860620060, MaxTime: 1750867200000, Version: 1, - Stats: TSDBBlocksStats{ + Stats: TSDBBlockStats{ NumSamples: 13701, NumSeries: 716, NumChunks: 716, }, - Compaction: TSDBBlocksCompaction{ + Compaction: TSDBBlockMetaCompaction{ Level: 1, Sources: []string{"01JZ8JKZY6XSK3PTDP9ZKRWT60"}, }, @@ -1245,6 +1259,488 @@ func TestAPIs(t *testing.T) { }, }, + // Block with all optional fields populated. + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01AAAAAAAAAAAAAAAAAAAAAA00", + "minTime": 1750860000000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 50000, + "numFloatSamples": 30000, + "numHistogramSamples": 20000, + "numSeries": 1000, + "numChunks": 2000, + "numTombstones": 5, + }, + "compaction": map[string]interface{}{ + "level": 3, + "sources": []interface{}{ + "01AAAAAAAAAAAAAAAAAAAAAA01", + "01AAAAAAAAAAAAAAAAAAAAAA02", + "01AAAAAAAAAAAAAAAAAAAAAA03", + }, + "deletable": true, + "parents": []interface{}{ + map[string]interface{}{ + "ulid": "01AAAAAAAAAAAAAAAAAAAAAA01", + "minTime": 1750853000000, + "maxTime": 1750860000000, + }, + map[string]interface{}{ + "ulid": "01AAAAAAAAAAAAAAAAAAAAAA02", + "minTime": 1750860000000, + "maxTime": 1750867200000, + }, + }, + "failed": true, + "hints": []interface{}{ + "deduplication", + "downsampling", + }, + }, + "version": 1, + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{{ + Ulid: "01AAAAAAAAAAAAAAAAAAAAAA00", + MinTime: 1750860000000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 50000, + NumFloatSamples: 30000, + NumHistogramSamples: 20000, + NumSeries: 1000, + NumChunks: 2000, + NumTombstones: 5, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 3, + Sources: []string{ + "01AAAAAAAAAAAAAAAAAAAAAA01", + "01AAAAAAAAAAAAAAAAAAAAAA02", + "01AAAAAAAAAAAAAAAAAAAAAA03", + }, + Deletable: true, + Parents: []TSDBBlockDesc{ + { + Ulid: "01AAAAAAAAAAAAAAAAAAAAAA01", + MinTime: 1750853000000, + MaxTime: 1750860000000, + }, + { + Ulid: "01AAAAAAAAAAAAAAAAAAAAAA02", + MinTime: 1750860000000, + MaxTime: 1750867200000, + }, + }, + Failed: true, + Hints: []string{"deduplication", "downsampling"}, + }, + }}, + }, + }, + + // Multiple blocks at different compaction levels. + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB01", + "minTime": 1750860000000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 5000, + "numSeries": 200, + "numChunks": 200, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01BBBBBBBBBBBBBBBBBBBBBB01", + }, + }, + "version": 1, + }, + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB02", + "minTime": 1750846800000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 25000, + "numSeries": 500, + "numChunks": 1500, + }, + "compaction": map[string]interface{}{ + "level": 2, + "sources": []interface{}{ + "01BBBBBBBBBBBBBBBBBBBBBB03", + "01BBBBBBBBBBBBBBBBBBBBBB04", + }, + "parents": []interface{}{ + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB03", + "minTime": 1750846800000, + "maxTime": 1750860000000, + }, + }, + }, + "version": 1, + }, + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB05", + "minTime": 1750820000000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 100000, + "numSeries": 1000, + "numChunks": 5000, + }, + "compaction": map[string]interface{}{ + "level": 3, + "sources": []interface{}{ + "01BBBBBBBBBBBBBBBBBBBBBB06", + "01BBBBBBBBBBBBBBBBBBBBBB07", + "01BBBBBBBBBBBBBBBBBBBBBB08", + }, + "parents": []interface{}{ + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB06", + "minTime": 1750820000000, + "maxTime": 1750840000000, + }, + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB07", + "minTime": 1750840000000, + "maxTime": 1750855000000, + }, + map[string]interface{}{ + "ulid": "01BBBBBBBBBBBBBBBBBBBBBB08", + "minTime": 1750855000000, + "maxTime": 1750867200000, + }, + }, + }, + "version": 1, + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{ + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB01", + MinTime: 1750860000000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 5000, + NumSeries: 200, + NumChunks: 200, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01BBBBBBBBBBBBBBBBBBBBBB01"}, + }, + }, + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB02", + MinTime: 1750846800000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 25000, + NumSeries: 500, + NumChunks: 1500, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 2, + Sources: []string{ + "01BBBBBBBBBBBBBBBBBBBBBB03", + "01BBBBBBBBBBBBBBBBBBBBBB04", + }, + Parents: []TSDBBlockDesc{ + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB03", + MinTime: 1750846800000, + MaxTime: 1750860000000, + }, + }, + }, + }, + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB05", + MinTime: 1750820000000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 100000, + NumSeries: 1000, + NumChunks: 5000, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 3, + Sources: []string{ + "01BBBBBBBBBBBBBBBBBBBBBB06", + "01BBBBBBBBBBBBBBBBBBBBBB07", + "01BBBBBBBBBBBBBBBBBBBBBB08", + }, + Parents: []TSDBBlockDesc{ + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB06", + MinTime: 1750820000000, + MaxTime: 1750840000000, + }, + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB07", + MinTime: 1750840000000, + MaxTime: 1750855000000, + }, + { + Ulid: "01BBBBBBBBBBBBBBBBBBBBBB08", + MinTime: 1750855000000, + MaxTime: 1750867200000, + }, + }, + }, + }, + }, + }, + }, + + // Null blocks field (server returns null instead of empty array). + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": nil, + }, + res: TSDBBlocksResult{ + Blocks: nil, + }, + }, + + // Block with missing optional stats field (should deserialize with zero values). + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01CCCCCCCCCCCCCCCCCCCCCC01", + "minTime": 1750860000000, + "maxTime": 1750867200000, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01CCCCCCCCCCCCCCCCCCCCCC01", + }, + }, + "version": 1, + // Note: no "stats" field + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{{ + Ulid: "01CCCCCCCCCCCCCCCCCCCCCC01", + MinTime: 1750860000000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{}, // zero values + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01CCCCCCCCCCCCCCCCCCCCCC01"}, + }, + }}, + }, + }, + + // Block with "out-of-order" hint (specific to Prometheus OOO feature). + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01DDDDDDDDDDDDDDDDDDDDDD01", + "minTime": 1750860000000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 1000, + "numSeries": 100, + "numChunks": 100, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01DDDDDDDDDDDDDDDDDDDDDD01", + }, + "hints": []interface{}{ + "out-of-order", + }, + }, + "version": 1, + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{{ + Ulid: "01DDDDDDDDDDDDDDDDDDDDDD01", + MinTime: 1750860000000, + MaxTime: 1750867200000, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 1000, + NumSeries: 100, + NumChunks: 100, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01DDDDDDDDDDDDDDDDDDDDDD01"}, + Hints: []string{"out-of-order"}, + }, + }}, + }, + }, + + // Block with zero-value time boundaries (edge case). + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01EEEEEEEEEEEEEEEEEEEEEE01", + "minTime": 0, + "maxTime": 0, + "stats": map[string]interface{}{ + "numSamples": 0, + "numSeries": 0, + "numChunks": 0, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01EEEEEEEEEEEEEEEEEEEEEE01", + }, + }, + "version": 1, + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{{ + Ulid: "01EEEEEEEEEEEEEEEEEEEEEE01", + MinTime: 0, + MaxTime: 0, + Version: 1, + Stats: TSDBBlockStats{ + NumSamples: 0, + NumSeries: 0, + NumChunks: 0, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01EEEEEEEEEEEEEEEEEEEEEE01"}, + }, + }}, + }, + }, + + // Block with different version values. + { + do: doTSDBBlocks(), + reqMethod: "GET", + reqPath: "/api/v1/status/tsdb/blocks", + inRes: map[string]interface{}{ + "blocks": []interface{}{ + map[string]interface{}{ + "ulid": "01FFFFFFFFFFFFFFFFFFFFFF01", + "minTime": 1750860000000, + "maxTime": 1750867200000, + "stats": map[string]interface{}{ + "numSamples": 500, + "numSeries": 50, + "numChunks": 50, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01FFFFFFFFFFFFFFFFFFFFFF01", + }, + }, + "version": 0, // Version 0 (legacy/unset) + }, + map[string]interface{}{ + "ulid": "01FFFFFFFFFFFFFFFFFFFFFF02", + "minTime": 1750867200000, + "maxTime": 1750874400000, + "stats": map[string]interface{}{ + "numSamples": 600, + "numSeries": 60, + "numChunks": 60, + }, + "compaction": map[string]interface{}{ + "level": 1, + "sources": []interface{}{ + "01FFFFFFFFFFFFFFFFFFFFFF02", + }, + }, + "version": 2, // Hypothetical future version + }, + }, + }, + res: TSDBBlocksResult{ + Blocks: []TSDBBlockMeta{ + { + Ulid: "01FFFFFFFFFFFFFFFFFFFFFF01", + MinTime: 1750860000000, + MaxTime: 1750867200000, + Version: 0, + Stats: TSDBBlockStats{ + NumSamples: 500, + NumSeries: 50, + NumChunks: 50, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01FFFFFFFFFFFFFFFFFFFFFF01"}, + }, + }, + { + Ulid: "01FFFFFFFFFFFFFFFFFFFFFF02", + MinTime: 1750867200000, + MaxTime: 1750874400000, + Version: 2, + Stats: TSDBBlockStats{ + NumSamples: 600, + NumSeries: 60, + NumChunks: 60, + }, + Compaction: TSDBBlockMetaCompaction{ + Level: 1, + Sources: []string{"01FFFFFFFFFFFFFFFFFFFFFF02"}, + }, + }, + }, + }, + }, + { do: doWalReply(), reqMethod: "GET", From 4765ce8aa6b66f2396625d9e97d8f08fa131ab26 Mon Sep 17 00:00:00 2001 From: TJ Hoplock Date: Thu, 29 Jan 2026 16:59:53 -0500 Subject: [PATCH 4/4] style: go fmt My commit hook didn't run it seems. Oops. Signed-off-by: TJ Hoplock --- api/prometheus/v1/api.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/prometheus/v1/api.go b/api/prometheus/v1/api.go index 7bfdd7149..451ccaecf 100644 --- a/api/prometheus/v1/api.go +++ b/api/prometheus/v1/api.go @@ -711,12 +711,12 @@ type TSDBBlocksResult struct { // Counterpart to prometheus/prometheus tsdb.BlockMeta: // https://github.com/prometheus/prometheus/blob/304dcdf6959d7a45530e9b6efa4080c5ca37dbf7/tsdb/block.go#L164 type TSDBBlockMeta struct { - Ulid string `json:"ulid"` - MinTime int64 `json:"minTime"` - MaxTime int64 `json:"maxTime"` - Stats TSDBBlockStats `json:"stats,omitempty"` + Ulid string `json:"ulid"` + MinTime int64 `json:"minTime"` + MaxTime int64 `json:"maxTime"` + Stats TSDBBlockStats `json:"stats,omitempty"` Compaction TSDBBlockMetaCompaction `json:"compaction"` - Version int `json:"version"` + Version int `json:"version"` } // TSDBBlockStats contains block stats for a single TSDB block.