1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "kll.h"
17 
18 #include "kll-quantiles.pb.h"
19 
20 #include <gtest/gtest.h>
21 
22 namespace dist_proc {
23 namespace aggregation {
24 
25 namespace {
26 
27 using zetasketch::android::AggregatorStateProto;
28 using zetasketch::android::kll_quantiles_state;
29 using zetasketch::android::KllQuantilesStateProto;
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 // --------------------- Tests for SerializeToProto ------------------------- //
33 
TEST(KllQuantileSerializationTest,AggregatorProtoFieldsAreCorrectlyPopulated)34 TEST(KllQuantileSerializationTest, AggregatorProtoFieldsAreCorrectlyPopulated) {
35     std::unique_ptr<KllQuantile> aggregator = KllQuantile::Create();
36     for (int i = 0; i < 50; i++) {
37         aggregator->Add(i);
38     }
39     EXPECT_EQ(aggregator->num_values(), 50);
40 
41     AggregatorStateProto aggregator_state = aggregator->SerializeToProto();
42     ASSERT_TRUE(aggregator_state.has_num_values());
43     EXPECT_EQ(aggregator_state.num_values(), 50);
44     EXPECT_EQ(aggregator_state.type(), zetasketch::android::KLL_QUANTILES);
45     EXPECT_EQ(aggregator_state.type(), 113);
46     EXPECT_EQ(aggregator_state.value_type(), zetasketch::android::DefaultOpsType::INT64);
47     EXPECT_EQ(aggregator_state.value_type(), 4);
48 }
49 
TEST(KllQuantileSerializationTest,QuantilesProtoFieldsAreCorrectlyPopulated)50 TEST(KllQuantileSerializationTest, QuantilesProtoFieldsAreCorrectlyPopulated) {
51     std::unique_ptr<KllQuantile> aggregator = KllQuantile::Create();
52     for (int i = 1; i <= 10; i++) {
53         aggregator->Add(i);
54     }
55     EXPECT_EQ(aggregator->num_values(), 10);
56 
57     AggregatorStateProto aggregator_state = aggregator->SerializeToProto();
58     EXPECT_EQ(aggregator_state.num_values(), 10);
59 
60     EXPECT_EQ(aggregator_state.type(), zetasketch::android::KLL_QUANTILES);
61     ASSERT_TRUE(aggregator_state.HasExtension(kll_quantiles_state));
62     const KllQuantilesStateProto& quantiles_state =
63             aggregator_state.GetExtension(kll_quantiles_state);
64 
65     ASSERT_TRUE(quantiles_state.has_k());
66     EXPECT_GE(quantiles_state.k(), 300);
67     EXPECT_LT(quantiles_state.k(), 5000);
68 
69     ASSERT_TRUE(quantiles_state.has_inv_eps());
70     EXPECT_EQ(quantiles_state.inv_eps(), 1000);
71 
72     // Min, max
73     ASSERT_TRUE(quantiles_state.has_min());
74     EXPECT_EQ(quantiles_state.min(), "\x1");
75     ASSERT_TRUE(quantiles_state.has_max());
76     EXPECT_EQ(quantiles_state.max(), "\xA");
77 
78     // Compactors
79     EXPECT_EQ(quantiles_state.compactors_size(), 1);
80     const KllQuantilesStateProto::Compactor& compactor = quantiles_state.compactors(0);
81     ASSERT_TRUE(compactor.has_packed_values());
82     EXPECT_EQ(compactor.packed_values(), "\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA");
83 
84     ASSERT_FALSE(quantiles_state.has_sampler());
85 }
86 
TEST(KllQuantileSerializationTest,QuantilesProtoFieldsAreCorrectlyPopulatedNonDefaultInvDeltaEps)87 TEST(KllQuantileSerializationTest, QuantilesProtoFieldsAreCorrectlyPopulatedNonDefaultInvDeltaEps) {
88     KllQuantileOptions options;
89     options.set_inv_delta(1000);
90     options.set_inv_eps(40);
91     std::unique_ptr<KllQuantile> aggregator = KllQuantile::Create(options);
92     for (int i = 5; i < 200; i++) {
93         aggregator->Add(i);
94     }
95     EXPECT_EQ(aggregator->num_values(), 195);
96 
97     AggregatorStateProto aggregator_state = aggregator->SerializeToProto();
98     EXPECT_EQ(aggregator_state.num_values(), 195);
99 
100     ASSERT_TRUE(aggregator_state.HasExtension(kll_quantiles_state));
101     const KllQuantilesStateProto& quantiles_state =
102             aggregator_state.GetExtension(kll_quantiles_state);
103 
104     ASSERT_TRUE(quantiles_state.has_k());
105     EXPECT_GE(quantiles_state.k(), 15);
106     EXPECT_LT(quantiles_state.k(), 200);
107 
108     ASSERT_TRUE(quantiles_state.has_inv_eps());
109     EXPECT_EQ(quantiles_state.inv_eps(), 40);
110 
111     // Min, max
112     ASSERT_TRUE(quantiles_state.has_min());
113     EXPECT_EQ(quantiles_state.min(), "\x5");
114     ASSERT_TRUE(quantiles_state.has_max());
115     EXPECT_EQ(quantiles_state.max(), "\xC7\x1");
116 
117     EXPECT_GT(quantiles_state.compactors_size(), 1);
118 }
119 
TEST(KllQuantileSerializationTest,QuantilesProtoFieldsAreCorrectlyPopulatedNonDefaultK)120 TEST(KllQuantileSerializationTest, QuantilesProtoFieldsAreCorrectlyPopulatedNonDefaultK) {
121     KllQuantileOptions options;
122     options.set_k(6000);
123     std::unique_ptr<KllQuantile> aggregator = KllQuantile::Create(options);
124     for (int i = 10; i <= 1000; i++) {
125         aggregator->Add(i);
126     }
127     EXPECT_EQ(aggregator->num_values(), 991);
128 
129     AggregatorStateProto aggregator_state = aggregator->SerializeToProto();
130     EXPECT_EQ(aggregator_state.num_values(), 991);
131 
132     ASSERT_TRUE(aggregator_state.HasExtension(kll_quantiles_state));
133     const KllQuantilesStateProto& quantiles_state =
134             aggregator_state.GetExtension(kll_quantiles_state);
135 
136     ASSERT_TRUE(quantiles_state.has_k());
137     EXPECT_EQ(quantiles_state.k(), 6000);
138 
139     // Min, max
140     ASSERT_TRUE(quantiles_state.has_min());
141     EXPECT_EQ(quantiles_state.min(), "\xA");
142     ASSERT_TRUE(quantiles_state.has_max());
143     EXPECT_EQ(quantiles_state.max(), "\xE8\a");
144 
145     EXPECT_EQ(quantiles_state.compactors_size(), 1);
146 }
147 
TEST(KllQuantileSerializationTest,EmptyQuantilesProto)148 TEST(KllQuantileSerializationTest, EmptyQuantilesProto) {
149     std::unique_ptr<KllQuantile> aggregator = KllQuantile::Create();
150 
151     AggregatorStateProto aggregator_state = aggregator->SerializeToProto();
152     EXPECT_EQ(aggregator->num_values(), 0);
153 
154     EXPECT_EQ(aggregator_state.type(), zetasketch::android::KLL_QUANTILES);
155     ASSERT_TRUE(aggregator_state.HasExtension(kll_quantiles_state));
156     aggregator_state.GetExtension(kll_quantiles_state);
157 
158     const KllQuantilesStateProto& quantiles_state =
159             aggregator_state.GetExtension(kll_quantiles_state);
160 
161     ASSERT_TRUE(quantiles_state.has_k());
162     EXPECT_GE(quantiles_state.k(), 1000);
163     EXPECT_LT(quantiles_state.k(), 5000);
164 
165     ASSERT_TRUE(quantiles_state.has_inv_eps());
166     EXPECT_EQ(quantiles_state.inv_eps(), 1000);
167 
168     ASSERT_FALSE(quantiles_state.has_min());
169     ASSERT_FALSE(quantiles_state.has_max());
170 
171     EXPECT_EQ(quantiles_state.compactors_size(), 0);
172     ASSERT_FALSE(quantiles_state.has_sampler());
173 }
174 }  // namespace
175 
176 }  // namespace aggregation
177 }  // namespace dist_proc
178