This is an automated email from the ASF dual-hosted git repository. hulk pushed a commit to branch 2.12 in repository https://gitbox.apache.org/repos/asf/kvrocks.git
commit e147ced4bcf2286aad6262f5feebf81b04d1e068 Author: git-hulk <[email protected]> AuthorDate: Thu Apr 17 20:41:30 2025 +0800 Comment out the tdigest and its test cases due to it's not production ready --- src/commands/cmd_tdigest.cc | 12 +- tests/cppunit/types/tdigest_test.cc | 452 +++++++++---------- tests/gocase/unit/type/tdigest/tdigest_test.go | 580 ++++++++++++------------- 3 files changed, 522 insertions(+), 522 deletions(-) diff --git a/src/commands/cmd_tdigest.cc b/src/commands/cmd_tdigest.cc index 166a22afb..a0f6bab4a 100644 --- a/src/commands/cmd_tdigest.cc +++ b/src/commands/cmd_tdigest.cc @@ -243,10 +243,10 @@ class CommandTDigestMax : public CommandTDigestMinMax { CommandTDigestMax() : CommandTDigestMinMax(false) {} }; -REDIS_REGISTER_COMMANDS(TDigest, MakeCmdAttr<CommandTDigestCreate>("tdigest.create", -2, "write", 1, 1, 1), - MakeCmdAttr<CommandTDigestInfo>("tdigest.info", 2, "read-only", 1, 1, 1), - MakeCmdAttr<CommandTDigestAdd>("tdigest.add", -3, "write", 1, 1, 1), - MakeCmdAttr<CommandTDigestMax>("tdigest.max", 2, "read-only", 1, 1, 1), - MakeCmdAttr<CommandTDigestMin>("tdigest.min", 2, "read-only", 1, 1, 1), - MakeCmdAttr<CommandTDigestReset>("tdigest.reset", 2, "write", 1, 1, 1)); +// REDIS_REGISTER_COMMANDS(TDigest, MakeCmdAttr<CommandTDigestCreate>("tdigest.create", -2, "write", 1, 1, 1), +// MakeCmdAttr<CommandTDigestInfo>("tdigest.info", 2, "read-only", 1, 1, 1), +// MakeCmdAttr<CommandTDigestAdd>("tdigest.add", -3, "write", 1, 1, 1), +// MakeCmdAttr<CommandTDigestMax>("tdigest.max", 2, "read-only", 1, 1, 1), +// MakeCmdAttr<CommandTDigestMin>("tdigest.min", 2, "read-only", 1, 1, 1), +// MakeCmdAttr<CommandTDigestReset>("tdigest.reset", 2, "write", 1, 1, 1)); } // namespace redis diff --git a/tests/cppunit/types/tdigest_test.cc b/tests/cppunit/types/tdigest_test.cc index 7d2b6e6e2..484aa7bfc 100644 --- a/tests/cppunit/types/tdigest_test.cc +++ b/tests/cppunit/types/tdigest_test.cc @@ -18,229 +18,229 @@ * */ -#include "types/tdigest.h" - -#include <fmt/format.h> -#include <glog/logging.h> -#include <gtest/gtest.h> - -#include <algorithm> -#include <cmath> -#include <memory> -#include <random> -#include <range/v3/algorithm/shuffle.hpp> -#include <range/v3/range.hpp> -#include <range/v3/view/chunk.hpp> -#include <range/v3/view/iota.hpp> -#include <range/v3/view/join.hpp> -#include <range/v3/view/transform.hpp> -#include <string> -#include <vector> - -#include "storage/redis_metadata.h" -#include "test_base.h" -#include "time_util.h" -#include "types/redis_tdigest.h" - -namespace { -constexpr std::random_device::result_type kSeed = 14863; // fixed seed for reproducibility - -std::vector<double> QuantileOf(const std::vector<double> &samples, const std::vector<double> &qs) { - std::vector<double> result; - result.reserve(qs.size()); - std::vector<double> sorted_samples = samples; - std::sort(sorted_samples.begin(), sorted_samples.end()); - for (auto q : qs) { - auto index = q * static_cast<double>(sorted_samples.size()); - if (index <= 1) { - result.push_back(sorted_samples.front()); - } else if (index >= static_cast<double>(sorted_samples.size() - 1)) { - result.push_back(sorted_samples.back()); - } else { - auto left = sorted_samples[static_cast<int>(index)]; - auto right = sorted_samples[static_cast<int>(index) + 1]; - auto diff = index - static_cast<int>(index); - result.push_back(left + (right - left) * diff); - } - } - return result; -} - -std::vector<std::pair<double, double>> QuantileIntervalOf(const std::vector<double> &samples, - const std::vector<double> &qs) { - std::vector<std::pair<double, double>> result; - result.reserve(qs.size()); - std::vector<double> sorted_samples = samples; - std::sort(sorted_samples.begin(), sorted_samples.end()); - for (auto q : qs) { - auto index = q * static_cast<double>(sorted_samples.size()); - if (index <= 1) { - result.emplace_back(sorted_samples.front(), sorted_samples.front()); - } else if (index >= static_cast<double>(sorted_samples.size() - 1)) { - result.emplace_back(sorted_samples.back(), sorted_samples.back()); - } else { - auto left = sorted_samples[static_cast<int>(index)]; - auto right = sorted_samples[static_cast<int>(index) + 1]; - result.emplace_back(left, right); - } - } - return result; -} - -std::vector<double> GenerateSamples(int count, double from, double to) { - std::vector<double> samples; - samples.reserve(count); - for (int i = 0; i < count; i++) { - samples.push_back(from + static_cast<double>(i) * (to - from) / static_cast<double>(count)); - } - return samples; -} - -std::vector<double> GenerateQuantiles(int count, bool with_head = false, bool with_tail = false) { - std::vector<double> qs; - qs.reserve(count); - for (int i = 1; i <= count; i++) { - qs.push_back(static_cast<double>(i) / static_cast<double>(count)); - } - if (with_head) { - qs.insert(qs.begin(), 0); - } - if (with_tail) { - qs.push_back(1); - } - return qs; -} - -} // namespace - -class RedisTDigestTest : public TestBase { - protected: - RedisTDigestTest() : name_("tdigest_test") { - tdigest_ = std::make_unique<redis::TDigest>(storage_.get(), "tdigest_ns"); - } - - std::string name_; - std::unique_ptr<redis::TDigest> tdigest_; -}; - -TEST_F(RedisTDigestTest, CentroidTest) { - Centroid c1{ - 2., - 3., - }; - Centroid c2{ - 3., - 4., - }; - - c1.Merge(c2); - - EXPECT_NEAR(c1.weight, 7., 0.01); - EXPECT_NEAR(c1.mean, 2.57, 0.01); -} - -TEST_F(RedisTDigestTest, Create) { - std::string test_digest_name = "test_digest_create" + std::to_string(util::GetTimeStampMS()); - bool exists = false; - auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); - ASSERT_FALSE(exists); - ASSERT_TRUE(status.ok()); - - status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); - ASSERT_TRUE(exists); - ASSERT_TRUE(status.IsInvalidArgument()); - - TDigestMetadata metadata; - auto get_status = tdigest_->GetMetaData(*ctx_, test_digest_name, &metadata); - ASSERT_TRUE(get_status.ok()) << get_status.ToString(); - ASSERT_EQ(metadata.compression, 100) << metadata.compression; -} - -TEST_F(RedisTDigestTest, Quantile) { - std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); - - bool exists = false; - auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); - ASSERT_FALSE(exists); - ASSERT_TRUE(status.ok()); - std::vector<double> samples = ranges::views::iota(1, 101) | ranges::views::transform([](int i) { return i; }) | - ranges::to<std::vector<double>>(); - - status = tdigest_->Add(*ctx_, test_digest_name, samples); - ASSERT_TRUE(status.ok()) << status.ToString(); - - std::vector<double> qs = {0.5, 0.9, 0.99}; - redis::TDigestQuantitleResult result; - status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &result); - ASSERT_TRUE(status.ok()) << status.ToString(); - ASSERT_EQ(result.quantiles.size(), qs.size()); - EXPECT_NEAR(result.quantiles[0], 50.5, 0.01); - EXPECT_NEAR(result.quantiles[1], 90.5, 0.01); - EXPECT_NEAR(result.quantiles[2], 100, 0.01); -} - -TEST_F(RedisTDigestTest, PlentyQuantile_10000_144) { - std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); - bool exists = false; - auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); - ASSERT_FALSE(exists); - ASSERT_TRUE(status.ok()); - - int sample_count = 10000; - int quantile_count = 144; - double from = -100; - double to = 100; - auto error_double = (to - from) / sample_count; - auto samples = GenerateSamples(sample_count, -100, 100); - status = tdigest_->Add(*ctx_, test_digest_name, samples); - ASSERT_TRUE(status.ok()) << status.ToString(); - - auto qs = GenerateQuantiles(quantile_count); - auto result = QuantileOf(samples, qs); - - redis::TDigestQuantitleResult tdigest_result; - status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &tdigest_result); - ASSERT_TRUE(status.ok()) << status.ToString(); - - for (int i = 0; i < quantile_count; i++) { - EXPECT_NEAR(tdigest_result.quantiles[i], result[i], error_double) << "quantile is: " << qs[i]; - } -} - -TEST_F(RedisTDigestTest, Add_2_times) { - std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); - - bool exists = false; - auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); - ASSERT_FALSE(exists); - ASSERT_TRUE(status.ok()); - - int sample_count = 17; - int quantile_count = 7; - auto samples = GenerateSamples(sample_count, -100, 100); - auto qs = GenerateQuantiles(quantile_count); - auto expect_result = QuantileIntervalOf(samples, qs); - std::shuffle(samples.begin(), samples.end(), std::mt19937(kSeed)); - - int group_count = 4; - auto samples_sub_group = - samples | ranges::views::chunk(sample_count / group_count) | ranges::to<std::vector<std::vector<double>>>(); - - for (const auto &s : samples_sub_group) { - status = tdigest_->Add(*ctx_, test_digest_name, s); - ASSERT_TRUE(status.ok()) << status.ToString(); - } - - redis::TDigestQuantitleResult tdigest_result; - status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &tdigest_result); - ASSERT_TRUE(status.ok()) << status.ToString(); - - for (int i = 0; i < quantile_count; i++) { - auto &[expect_down, expect_upper] = expect_result[i]; - auto got = tdigest_result.quantiles[i]; - EXPECT_GE(got, expect_down) << fmt::format("quantile is {}, should in interval [{}, {}]", qs[i], expect_down, - expect_upper); - EXPECT_LE(got, expect_upper) << fmt::format("quantile is {}, should in interval [{}, {}]", qs[i], expect_down, - expect_upper); - } -} +// #include "types/tdigest.h" +// +// #include <fmt/format.h> +// #include <glog/logging.h> +// #include <gtest/gtest.h> +// +// #include <algorithm> +// #include <cmath> +// #include <memory> +// #include <random> +// #include <range/v3/algorithm/shuffle.hpp> +// #include <range/v3/range.hpp> +// #include <range/v3/view/chunk.hpp> +// #include <range/v3/view/iota.hpp> +// #include <range/v3/view/join.hpp> +// #include <range/v3/view/transform.hpp> +// #include <string> +// #include <vector> +// +// #include "storage/redis_metadata.h" +// #include "test_base.h" +// #include "time_util.h" +// #include "types/redis_tdigest.h" +// +// namespace { +// constexpr std::random_device::result_type kSeed = 14863; // fixed seed for reproducibility +// +// std::vector<double> QuantileOf(const std::vector<double> &samples, const std::vector<double> &qs) { +// std::vector<double> result; +// result.reserve(qs.size()); +// std::vector<double> sorted_samples = samples; +// std::sort(sorted_samples.begin(), sorted_samples.end()); +// for (auto q : qs) { +// auto index = q * static_cast<double>(sorted_samples.size()); +// if (index <= 1) { +// result.push_back(sorted_samples.front()); +// } else if (index >= static_cast<double>(sorted_samples.size() - 1)) { +// result.push_back(sorted_samples.back()); +// } else { +// auto left = sorted_samples[static_cast<int>(index)]; +// auto right = sorted_samples[static_cast<int>(index) + 1]; +// auto diff = index - static_cast<int>(index); +// result.push_back(left + (right - left) * diff); +// } +// } +// return result; +// } +// +// std::vector<std::pair<double, double>> QuantileIntervalOf(const std::vector<double> &samples, +// const std::vector<double> &qs) { +// std::vector<std::pair<double, double>> result; +// result.reserve(qs.size()); +// std::vector<double> sorted_samples = samples; +// std::sort(sorted_samples.begin(), sorted_samples.end()); +// for (auto q : qs) { +// auto index = q * static_cast<double>(sorted_samples.size()); +// if (index <= 1) { +// result.emplace_back(sorted_samples.front(), sorted_samples.front()); +// } else if (index >= static_cast<double>(sorted_samples.size() - 1)) { +// result.emplace_back(sorted_samples.back(), sorted_samples.back()); +// } else { +// auto left = sorted_samples[static_cast<int>(index)]; +// auto right = sorted_samples[static_cast<int>(index) + 1]; +// result.emplace_back(left, right); +// } +// } +// return result; +// } +// +// std::vector<double> GenerateSamples(int count, double from, double to) { +// std::vector<double> samples; +// samples.reserve(count); +// for (int i = 0; i < count; i++) { +// samples.push_back(from + static_cast<double>(i) * (to - from) / static_cast<double>(count)); +// } +// return samples; +// } +// +// std::vector<double> GenerateQuantiles(int count, bool with_head = false, bool with_tail = false) { +// std::vector<double> qs; +// qs.reserve(count); +// for (int i = 1; i <= count; i++) { +// qs.push_back(static_cast<double>(i) / static_cast<double>(count)); +// } +// if (with_head) { +// qs.insert(qs.begin(), 0); +// } +// if (with_tail) { +// qs.push_back(1); +// } +// return qs; +// } +// +// } // namespace +// +// class RedisTDigestTest : public TestBase { +// protected: +// RedisTDigestTest() : name_("tdigest_test") { +// tdigest_ = std::make_unique<redis::TDigest>(storage_.get(), "tdigest_ns"); +// } +// +// std::string name_; +// std::unique_ptr<redis::TDigest> tdigest_; +// }; +// +// TEST_F(RedisTDigestTest, CentroidTest) { +// Centroid c1{ +// 2., +// 3., +// }; +// Centroid c2{ +// 3., +// 4., +// }; +// +// c1.Merge(c2); +// +// EXPECT_NEAR(c1.weight, 7., 0.01); +// EXPECT_NEAR(c1.mean, 2.57, 0.01); +// } +// +// TEST_F(RedisTDigestTest, Create) { +// std::string test_digest_name = "test_digest_create" + std::to_string(util::GetTimeStampMS()); +// bool exists = false; +// auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); +// ASSERT_FALSE(exists); +// ASSERT_TRUE(status.ok()); +// +// status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); +// ASSERT_TRUE(exists); +// ASSERT_TRUE(status.IsInvalidArgument()); +// +// TDigestMetadata metadata; +// auto get_status = tdigest_->GetMetaData(*ctx_, test_digest_name, &metadata); +// ASSERT_TRUE(get_status.ok()) << get_status.ToString(); +// ASSERT_EQ(metadata.compression, 100) << metadata.compression; +// } +// +// TEST_F(RedisTDigestTest, Quantile) { +// std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); +// +// bool exists = false; +// auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); +// ASSERT_FALSE(exists); +// ASSERT_TRUE(status.ok()); +// std::vector<double> samples = ranges::views::iota(1, 101) | ranges::views::transform([](int i) { return i; }) | +// ranges::to<std::vector<double>>(); +// +// status = tdigest_->Add(*ctx_, test_digest_name, samples); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// +// std::vector<double> qs = {0.5, 0.9, 0.99}; +// redis::TDigestQuantitleResult result; +// status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &result); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// ASSERT_EQ(result.quantiles.size(), qs.size()); +// EXPECT_NEAR(result.quantiles[0], 50.5, 0.01); +// EXPECT_NEAR(result.quantiles[1], 90.5, 0.01); +// EXPECT_NEAR(result.quantiles[2], 100, 0.01); +// } +// +// TEST_F(RedisTDigestTest, PlentyQuantile_10000_144) { +// std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); +// bool exists = false; +// auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); +// ASSERT_FALSE(exists); +// ASSERT_TRUE(status.ok()); +// +// int sample_count = 10000; +// int quantile_count = 144; +// double from = -100; +// double to = 100; +// auto error_double = (to - from) / sample_count; +// auto samples = GenerateSamples(sample_count, -100, 100); +// status = tdigest_->Add(*ctx_, test_digest_name, samples); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// +// auto qs = GenerateQuantiles(quantile_count); +// auto result = QuantileOf(samples, qs); +// +// redis::TDigestQuantitleResult tdigest_result; +// status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &tdigest_result); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// +// for (int i = 0; i < quantile_count; i++) { +// EXPECT_NEAR(tdigest_result.quantiles[i], result[i], error_double) << "quantile is: " << qs[i]; +// } +// } +// +// TEST_F(RedisTDigestTest, Add_2_times) { +// std::string test_digest_name = "test_digest_quantile" + std::to_string(util::GetTimeStampMS()); +// +// bool exists = false; +// auto status = tdigest_->Create(*ctx_, test_digest_name, {100}, &exists); +// ASSERT_FALSE(exists); +// ASSERT_TRUE(status.ok()); +// +// int sample_count = 17; +// int quantile_count = 7; +// auto samples = GenerateSamples(sample_count, -100, 100); +// auto qs = GenerateQuantiles(quantile_count); +// auto expect_result = QuantileIntervalOf(samples, qs); +// std::shuffle(samples.begin(), samples.end(), std::mt19937(kSeed)); +// +// int group_count = 4; +// auto samples_sub_group = +// samples | ranges::views::chunk(sample_count / group_count) | ranges::to<std::vector<std::vector<double>>>(); +// +// for (const auto &s : samples_sub_group) { +// status = tdigest_->Add(*ctx_, test_digest_name, s); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// } +// +// redis::TDigestQuantitleResult tdigest_result; +// status = tdigest_->Quantile(*ctx_, test_digest_name, qs, &tdigest_result); +// ASSERT_TRUE(status.ok()) << status.ToString(); +// +// for (int i = 0; i < quantile_count; i++) { +// auto &[expect_down, expect_upper] = expect_result[i]; +// auto got = tdigest_result.quantiles[i]; +// EXPECT_GE(got, expect_down) << fmt::format("quantile is {}, should in interval [{}, {}]", qs[i], expect_down, +// expect_upper); +// EXPECT_LE(got, expect_upper) << fmt::format("quantile is {}, should in interval [{}, {}]", qs[i], expect_down, +// expect_upper); +// } +// } diff --git a/tests/gocase/unit/type/tdigest/tdigest_test.go b/tests/gocase/unit/type/tdigest/tdigest_test.go index d3f118004..78db9bbfa 100644 --- a/tests/gocase/unit/type/tdigest/tdigest_test.go +++ b/tests/gocase/unit/type/tdigest/tdigest_test.go @@ -21,293 +21,293 @@ package tdigest -import ( - "context" - "testing" - - "github.com/apache/kvrocks/tests/gocase/util" - "github.com/stretchr/testify/require" -) - -const ( - errMsgWrongNumberArg = "wrong number of arguments" - errMsgParseCompression = "error parsing compression parameter" - errMsgNeedToBePositive = "compression parameter needs to be a positive integer" - errMsgMustInRange = "compression must be between 1 and 1000" - errMsgKeyAlreadyExists = "key already exists" - errMsgKeyNotExist = "key does not exist" -) - -type tdigestInfo struct { - Compression int64 - Capacity int64 - MergedNodes int64 - UnmergedNodes int64 - MergedWeight int64 - UnmergedWeight int64 - Observations int64 - TotalCompressions int64 - // memory usgae is not useful, we do not support it now -} - -func toTdigestInfo(t *testing.T, value interface{}) tdigestInfo { - require.IsType(t, map[interface{}]interface{}{}, value) - v := value.(map[interface{}]interface{}) - return tdigestInfo{ - Compression: v["Compression"].(int64), - Capacity: v["Capacity"].(int64), - MergedNodes: v["Merged nodes"].(int64), - UnmergedNodes: v["Unmerged nodes"].(int64), - MergedWeight: v["Merged weight"].(int64), - UnmergedWeight: v["Unmerged weight"].(int64), - Observations: v["Observations"].(int64), - TotalCompressions: v["Total compressions"].(int64), - } -} - -func TestTDigest(t *testing.T) { - configOptions := []util.ConfigOptions{ - { - Name: "txn-context-enabled", - Options: []string{"yes", "no"}, - ConfigType: util.YesNo, - }, - } - - configsMatrix, err := util.GenerateConfigsMatrix(configOptions) - require.NoError(t, err) - - for _, configs := range configsMatrix { - tdigestTests(t, configs) - } -} - -func tdigestTests(t *testing.T, configs util.KvrocksServerConfigs) { - srv := util.StartServer(t, configs) - defer srv.Close() - ctx := context.Background() - rdb := srv.NewClient() - defer func() { require.NoError(t, rdb.Close()) }() - - t.Run("tdigest.create with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_create_" - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "hahah").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "1", "hahah").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "hahah").Err(), errMsgParseCompression) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "0").Err(), errMsgNeedToBePositive) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "-1").Err(), errMsgNeedToBePositive) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "0.1").Err(), errMsgParseCompression) - - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err()) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err(), errMsgKeyAlreadyExists) - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key1", "compression", "1000").Err()) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "1001").Err(), errMsgMustInRange) - }) - - t.Run("tdigest.info with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_info_" - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key", "hahah").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key").Err(), errMsgKeyNotExist) - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err()) - { - rsp := rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key0") - require.NoError(t, rsp.Err()) - info := toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 1, info.Compression) - require.EqualValues(t, 1*6+10, info.Capacity) - require.EqualValues(t, 0, info.MergedNodes) - require.EqualValues(t, 0, info.UnmergedNodes) - require.EqualValues(t, 0, info.MergedWeight) - require.EqualValues(t, 0, info.UnmergedWeight) - require.EqualValues(t, 0, info.Observations) - require.EqualValues(t, 0, info.TotalCompressions) - } - - { - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key1", "compression", "1000").Err()) - rsp := rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key1") - require.NoError(t, rsp.Err()) - info := toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 1000, info.Compression) - require.EqualValues(t, 1024, info.Capacity) // max is 1024 - require.EqualValues(t, 0, info.MergedNodes) - require.EqualValues(t, 0, info.UnmergedNodes) - require.EqualValues(t, 0, info.MergedWeight) - require.EqualValues(t, 0, info.UnmergedWeight) - require.EqualValues(t, 0, info.Observations) - require.EqualValues(t, 0, info.TotalCompressions) - } - }) - - t.Run("tdigest.add with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_add_" - - // Satisfy the number of parameters - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"key").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"key", "abc").Err(), "not a valid float") - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"nonexistent", "1.0").Err(), errMsgKeyNotExist) - - // Test adding values to a key - key := keyPrefix + "test1" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.0").Err()) - - rsp := rdb.Do(ctx, "TDIGEST.INFO", key) - require.NoError(t, rsp.Err()) - info := toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 1, info.UnmergedNodes) - require.EqualValues(t, 1, info.Observations) - - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "2.0", "3.0", "4.0", "5.0").Err()) - - rsp = rdb.Do(ctx, "TDIGEST.INFO", key) - require.NoError(t, rsp.Err()) - info = toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 6, info.Observations) - - // Test adding values to a key with compression - key2 := keyPrefix + "test2" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key2, "compression", "100").Err()) - - args := []interface{}{key2} - for i := 1; i <= 1000; i++ { - args = append(args, float64(i)) - } - require.NoError(t, rdb.Do(ctx, append([]interface{}{"TDIGEST.ADD"}, args...)...).Err()) - - rsp = rdb.Do(ctx, "TDIGEST.INFO", key2) - require.NoError(t, rsp.Err()) - info = toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 1000, info.Observations) - - // Test adding values to a key with compression and merge node - key3 := keyPrefix + "test3" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key3, "compression", "10").Err()) - - args = []interface{}{key3} - for i := 1; i <= 100; i++ { - args = append(args, float64(i%10)) - } - require.NoError(t, rdb.Do(ctx, append([]interface{}{"TDIGEST.ADD"}, args...)...).Err()) - - rsp = rdb.Do(ctx, "TDIGEST.INFO", key3) - require.NoError(t, rsp.Err()) - info = toTdigestInfo(t, rsp.Val()) - - require.Greater(t, info.MergedNodes, int64(0)) - require.Greater(t, info.MergedWeight, int64(0)) - require.EqualValues(t, 100, info.Observations) - require.Greater(t, info.TotalCompressions, int64(0)) - }) - - t.Run("tdigest.max with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_max_" - - // Test invalid arguments - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MAX").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MAX", keyPrefix+"nonexistent").Err(), errMsgKeyNotExist) - - // Test with empty tdigest - key := keyPrefix + "test1" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) - rsp := rdb.Do(ctx, "TDIGEST.MAX", key) - require.NoError(t, rsp.Err()) - require.EqualValues(t, rsp.Val(), "nan") - - // Test with single value - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.5").Err()) - rsp = rdb.Do(ctx, "TDIGEST.MAX", key) - require.NoError(t, rsp.Err()) - require.Equal(t, "42.5", rsp.Val()) - - // Test with multiple values - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "100.5", "50.5", "-10.5").Err()) - rsp = rdb.Do(ctx, "TDIGEST.MAX", key) - require.NoError(t, rsp.Err()) - require.Equal(t, "100.5", rsp.Val()) - }) - - t.Run("tdigest.min with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_min_" - - // Test invalid arguments - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MIN").Err(), errMsgWrongNumberArg) - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MIN", keyPrefix+"nonexistent").Err(), errMsgKeyNotExist) - - // Test with empty tdigest - key := keyPrefix + "test1" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) - rsp := rdb.Do(ctx, "TDIGEST.MIN", key) - require.NoError(t, rsp.Err()) - require.EqualValues(t, rsp.Val(), "nan") - - // Test with single value - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.5").Err()) - rsp = rdb.Do(ctx, "TDIGEST.MIN", key) - require.NoError(t, rsp.Err()) - require.Equal(t, "42.5", rsp.Val()) - - // Test with multiple values - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "100.5", "50.5", "-10.5").Err()) - rsp = rdb.Do(ctx, "TDIGEST.MIN", key) - require.NoError(t, rsp.Err()) - require.Equal(t, "-10.5", rsp.Val()) - }) - t.Run("tdigest.reset with different arguments", func(t *testing.T) { - keyPrefix := "tdigest_reset_" - - // Testing with no arguments to .RESET - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.RESET").Err(), errMsgWrongNumberArg) - - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"mydigest", "compression", "101").Err()) - - key := keyPrefix + "mydigest" - // Adding some data to digest - require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "-84.3", "199.3", "343.34", "12.34").Err()) - - // Checking MIN value to ensure data was added - rsp := rdb.Do(ctx, "TDIGEST.MIN", key) - require.NoError(t, rsp.Err()) - require.EqualValues(t, rsp.Val(), "-84.3") - - // Reset on a non-existent key - require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.RESET", keyPrefix+"notexist").Err(), errMsgKeyNotExist) - - // Get TDIGEST.INFO before reset - rsp = rdb.Do(ctx, "TDIGEST.INFO", key) - require.NoError(t, rsp.Err()) - infoBeforeReset := toTdigestInfo(t, rsp.Val()) - - // Perform the reset - require.NoError(t, rdb.Do(ctx, "TDIGEST.RESET", key).Err()) - - // Get TDIGEST.INFO after reset - rsp = rdb.Do(ctx, "TDIGEST.INFO", key) - require.NoError(t, rsp.Err()) - infoAfterReset := toTdigestInfo(t, rsp.Val()) - - // Ensure capacity remains unchanged - require.EqualValues(t, infoBeforeReset.Capacity, infoAfterReset.Capacity) - require.EqualValues(t, 101, infoAfterReset.Compression) - require.EqualValues(t, 0, infoAfterReset.MergedNodes) - require.EqualValues(t, 0, infoAfterReset.UnmergedNodes) - require.EqualValues(t, 0, infoAfterReset.Observations) - require.EqualValues(t, 0, infoAfterReset.TotalCompressions) - - // Reset on an empty digest - emptyDigestKey := keyPrefix + "empty" - require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", emptyDigestKey, "COMPRESSION", "100").Err()) - rsp = rdb.Do(ctx, "TDIGEST.RESET", emptyDigestKey) - require.NoError(t, rsp.Err()) - - // Ensure empty digest's capacity remains the same - rsp = rdb.Do(ctx, "TDIGEST.INFO", emptyDigestKey) - require.NoError(t, rsp.Err()) - infoAfterEmptyReset := toTdigestInfo(t, rsp.Val()) - require.EqualValues(t, 100, infoAfterEmptyReset.Compression) - }) -} +// import ( +// "context" +// "testing" +// +// "github.com/apache/kvrocks/tests/gocase/util" +// "github.com/stretchr/testify/require" +// ) +// +// const ( +// errMsgWrongNumberArg = "wrong number of arguments" +// errMsgParseCompression = "error parsing compression parameter" +// errMsgNeedToBePositive = "compression parameter needs to be a positive integer" +// errMsgMustInRange = "compression must be between 1 and 1000" +// errMsgKeyAlreadyExists = "key already exists" +// errMsgKeyNotExist = "key does not exist" +// ) +// +// type tdigestInfo struct { +// Compression int64 +// Capacity int64 +// MergedNodes int64 +// UnmergedNodes int64 +// MergedWeight int64 +// UnmergedWeight int64 +// Observations int64 +// TotalCompressions int64 +// // memory usgae is not useful, we do not support it now +// } +// +// func toTdigestInfo(t *testing.T, value interface{}) tdigestInfo { +// require.IsType(t, map[interface{}]interface{}{}, value) +// v := value.(map[interface{}]interface{}) +// return tdigestInfo{ +// Compression: v["Compression"].(int64), +// Capacity: v["Capacity"].(int64), +// MergedNodes: v["Merged nodes"].(int64), +// UnmergedNodes: v["Unmerged nodes"].(int64), +// MergedWeight: v["Merged weight"].(int64), +// UnmergedWeight: v["Unmerged weight"].(int64), +// Observations: v["Observations"].(int64), +// TotalCompressions: v["Total compressions"].(int64), +// } +// } +// +// func TestTDigest(t *testing.T) { +// configOptions := []util.ConfigOptions{ +// { +// Name: "txn-context-enabled", +// Options: []string{"yes", "no"}, +// ConfigType: util.YesNo, +// }, +// } +// +// configsMatrix, err := util.GenerateConfigsMatrix(configOptions) +// require.NoError(t, err) +// +// for _, configs := range configsMatrix { +// tdigestTests(t, configs) +// } +// } +// +// func tdigestTests(t *testing.T, configs util.KvrocksServerConfigs) { +// srv := util.StartServer(t, configs) +// defer srv.Close() +// ctx := context.Background() +// rdb := srv.NewClient() +// defer func() { require.NoError(t, rdb.Close()) }() +// +// t.Run("tdigest.create with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_create_" +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "hahah").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "1", "hahah").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "hahah").Err(), errMsgParseCompression) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "0").Err(), errMsgNeedToBePositive) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "-1").Err(), errMsgNeedToBePositive) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "0.1").Err(), errMsgParseCompression) +// +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err()) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err(), errMsgKeyAlreadyExists) +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key1", "compression", "1000").Err()) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key", "compression", "1001").Err(), errMsgMustInRange) +// }) +// +// t.Run("tdigest.info with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_info_" +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key", "hahah").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key").Err(), errMsgKeyNotExist) +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key0", "compression", "1").Err()) +// { +// rsp := rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key0") +// require.NoError(t, rsp.Err()) +// info := toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 1, info.Compression) +// require.EqualValues(t, 1*6+10, info.Capacity) +// require.EqualValues(t, 0, info.MergedNodes) +// require.EqualValues(t, 0, info.UnmergedNodes) +// require.EqualValues(t, 0, info.MergedWeight) +// require.EqualValues(t, 0, info.UnmergedWeight) +// require.EqualValues(t, 0, info.Observations) +// require.EqualValues(t, 0, info.TotalCompressions) +// } +// +// { +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"key1", "compression", "1000").Err()) +// rsp := rdb.Do(ctx, "TDIGEST.INFO", keyPrefix+"key1") +// require.NoError(t, rsp.Err()) +// info := toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 1000, info.Compression) +// require.EqualValues(t, 1024, info.Capacity) // max is 1024 +// require.EqualValues(t, 0, info.MergedNodes) +// require.EqualValues(t, 0, info.UnmergedNodes) +// require.EqualValues(t, 0, info.MergedWeight) +// require.EqualValues(t, 0, info.UnmergedWeight) +// require.EqualValues(t, 0, info.Observations) +// require.EqualValues(t, 0, info.TotalCompressions) +// } +// }) +// +// t.Run("tdigest.add with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_add_" +// +// // Satisfy the number of parameters +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"key").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"key", "abc").Err(), "not a valid float") +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.ADD", keyPrefix+"nonexistent", "1.0").Err(), errMsgKeyNotExist) +// +// // Test adding values to a key +// key := keyPrefix + "test1" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.0").Err()) +// +// rsp := rdb.Do(ctx, "TDIGEST.INFO", key) +// require.NoError(t, rsp.Err()) +// info := toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 1, info.UnmergedNodes) +// require.EqualValues(t, 1, info.Observations) +// +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "2.0", "3.0", "4.0", "5.0").Err()) +// +// rsp = rdb.Do(ctx, "TDIGEST.INFO", key) +// require.NoError(t, rsp.Err()) +// info = toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 6, info.Observations) +// +// // Test adding values to a key with compression +// key2 := keyPrefix + "test2" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key2, "compression", "100").Err()) +// +// args := []interface{}{key2} +// for i := 1; i <= 1000; i++ { +// args = append(args, float64(i)) +// } +// require.NoError(t, rdb.Do(ctx, append([]interface{}{"TDIGEST.ADD"}, args...)...).Err()) +// +// rsp = rdb.Do(ctx, "TDIGEST.INFO", key2) +// require.NoError(t, rsp.Err()) +// info = toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 1000, info.Observations) +// +// // Test adding values to a key with compression and merge node +// key3 := keyPrefix + "test3" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key3, "compression", "10").Err()) +// +// args = []interface{}{key3} +// for i := 1; i <= 100; i++ { +// args = append(args, float64(i%10)) +// } +// require.NoError(t, rdb.Do(ctx, append([]interface{}{"TDIGEST.ADD"}, args...)...).Err()) +// +// rsp = rdb.Do(ctx, "TDIGEST.INFO", key3) +// require.NoError(t, rsp.Err()) +// info = toTdigestInfo(t, rsp.Val()) +// +// require.Greater(t, info.MergedNodes, int64(0)) +// require.Greater(t, info.MergedWeight, int64(0)) +// require.EqualValues(t, 100, info.Observations) +// require.Greater(t, info.TotalCompressions, int64(0)) +// }) +// +// t.Run("tdigest.max with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_max_" +// +// // Test invalid arguments +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MAX").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MAX", keyPrefix+"nonexistent").Err(), errMsgKeyNotExist) +// +// // Test with empty tdigest +// key := keyPrefix + "test1" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) +// rsp := rdb.Do(ctx, "TDIGEST.MAX", key) +// require.NoError(t, rsp.Err()) +// require.EqualValues(t, rsp.Val(), "nan") +// +// // Test with single value +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.5").Err()) +// rsp = rdb.Do(ctx, "TDIGEST.MAX", key) +// require.NoError(t, rsp.Err()) +// require.Equal(t, "42.5", rsp.Val()) +// +// // Test with multiple values +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "100.5", "50.5", "-10.5").Err()) +// rsp = rdb.Do(ctx, "TDIGEST.MAX", key) +// require.NoError(t, rsp.Err()) +// require.Equal(t, "100.5", rsp.Val()) +// }) +// +// t.Run("tdigest.min with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_min_" +// +// // Test invalid arguments +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MIN").Err(), errMsgWrongNumberArg) +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.MIN", keyPrefix+"nonexistent").Err(), errMsgKeyNotExist) +// +// // Test with empty tdigest +// key := keyPrefix + "test1" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", key, "compression", "100").Err()) +// rsp := rdb.Do(ctx, "TDIGEST.MIN", key) +// require.NoError(t, rsp.Err()) +// require.EqualValues(t, rsp.Val(), "nan") +// +// // Test with single value +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "42.5").Err()) +// rsp = rdb.Do(ctx, "TDIGEST.MIN", key) +// require.NoError(t, rsp.Err()) +// require.Equal(t, "42.5", rsp.Val()) +// +// // Test with multiple values +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "1.0", "100.5", "50.5", "-10.5").Err()) +// rsp = rdb.Do(ctx, "TDIGEST.MIN", key) +// require.NoError(t, rsp.Err()) +// require.Equal(t, "-10.5", rsp.Val()) +// }) +// t.Run("tdigest.reset with different arguments", func(t *testing.T) { +// keyPrefix := "tdigest_reset_" +// +// // Testing with no arguments to .RESET +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.RESET").Err(), errMsgWrongNumberArg) +// +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", keyPrefix+"mydigest", "compression", "101").Err()) +// +// key := keyPrefix + "mydigest" +// // Adding some data to digest +// require.NoError(t, rdb.Do(ctx, "TDIGEST.ADD", key, "-84.3", "199.3", "343.34", "12.34").Err()) +// +// // Checking MIN value to ensure data was added +// rsp := rdb.Do(ctx, "TDIGEST.MIN", key) +// require.NoError(t, rsp.Err()) +// require.EqualValues(t, rsp.Val(), "-84.3") +// +// // Reset on a non-existent key +// require.ErrorContains(t, rdb.Do(ctx, "TDIGEST.RESET", keyPrefix+"notexist").Err(), errMsgKeyNotExist) +// +// // Get TDIGEST.INFO before reset +// rsp = rdb.Do(ctx, "TDIGEST.INFO", key) +// require.NoError(t, rsp.Err()) +// infoBeforeReset := toTdigestInfo(t, rsp.Val()) +// +// // Perform the reset +// require.NoError(t, rdb.Do(ctx, "TDIGEST.RESET", key).Err()) +// +// // Get TDIGEST.INFO after reset +// rsp = rdb.Do(ctx, "TDIGEST.INFO", key) +// require.NoError(t, rsp.Err()) +// infoAfterReset := toTdigestInfo(t, rsp.Val()) +// +// // Ensure capacity remains unchanged +// require.EqualValues(t, infoBeforeReset.Capacity, infoAfterReset.Capacity) +// require.EqualValues(t, 101, infoAfterReset.Compression) +// require.EqualValues(t, 0, infoAfterReset.MergedNodes) +// require.EqualValues(t, 0, infoAfterReset.UnmergedNodes) +// require.EqualValues(t, 0, infoAfterReset.Observations) +// require.EqualValues(t, 0, infoAfterReset.TotalCompressions) +// +// // Reset on an empty digest +// emptyDigestKey := keyPrefix + "empty" +// require.NoError(t, rdb.Do(ctx, "TDIGEST.CREATE", emptyDigestKey, "COMPRESSION", "100").Err()) +// rsp = rdb.Do(ctx, "TDIGEST.RESET", emptyDigestKey) +// require.NoError(t, rsp.Err()) +// +// // Ensure empty digest's capacity remains the same +// rsp = rdb.Do(ctx, "TDIGEST.INFO", emptyDigestKey) +// require.NoError(t, rsp.Err()) +// infoAfterEmptyReset := toTdigestInfo(t, rsp.Val()) +// require.EqualValues(t, 100, infoAfterEmptyReset.Compression) +// }) +// }
