Kinetica   C#   API  Version 7.2.3.1
AsyncAggregateTests.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Threading.Tasks;
4 using Xunit;
6 using kinetica;
7 
9 {
14  [Trait("Category", "Integration")]
15  [Trait("Category", "Async")]
16  public class AsyncAggregateTests
17  {
21  private async Task<string> SetupNumericTableAsync(TestContext ctx, int numRecords)
22  {
23  var tableName = ctx.QualifiedTable("numeric_table");
24 
25  // Create table using SQL
26  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT NOT NULL, value DOUBLE, category VARCHAR(16), score INT, PRIMARY KEY (id))");
27 
28  // Insert records with varying data
29  for (int i = 0; i < numRecords; i++)
30  {
31  var category = (i % 3) switch
32  {
33  0 => "A",
34  1 => "B",
35  _ => "C"
36  };
37  var value = i * 1.5;
38  var score = i % 10;
39  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} (id, value, category, score) VALUES ({i}, {value}, '{category}', {score})");
40  }
41 
42  return tableName;
43  }
44 
45  // ============================================================================
46  // AGGREGATE UNIQUE TESTS
47  // ============================================================================
48 
49  [Fact]
50  public async Task TestAggregateUniqueBasicAsync()
51  {
52  using var ctx = new TestContext("async_agg_unique_basic");
53  var tableName = await SetupNumericTableAsync(ctx, 30);
54 
55  // Get unique categories (should be A, B, C)
56  var resp = await ctx.Kinetica.AggregateUniqueAsync(tableName, "category", 0, -9999, new Dictionary<string, string>());
57 
58  // Response has data as IList<KineticaRecord> - should have 3 unique categories
59  Assert.Equal(3, resp.data.Count);
60  }
61 
62  [Fact]
63  public async Task TestAggregateUniqueNumericAsync()
64  {
65  using var ctx = new TestContext("async_agg_unique_num");
66  var tableName = await SetupNumericTableAsync(ctx, 30);
67 
68  // Get unique scores (0-9, repeating pattern)
69  var resp = await ctx.Kinetica.AggregateUniqueAsync(tableName, "score", 0, -9999, new Dictionary<string, string>());
70 
71  // Should have 10 unique scores (0-9)
72  Assert.Equal(10, resp.data.Count);
73  }
74 
75  [Fact]
77  {
78  using var ctx = new TestContext("async_agg_unique_limit");
79  var tableName = await SetupNumericTableAsync(ctx, 30);
80 
81  // Get unique categories with limit
82  var resp = await ctx.Kinetica.AggregateUniqueAsync(tableName, "category", 0, 2, new Dictionary<string, string>());
83 
84  // Should be limited to 2
85  Assert.Equal(2, resp.data.Count);
86  }
87 
88  [Fact]
90  {
91  using var ctx = new TestContext("async_agg_unique_empty");
92  var tableName = await SetupNumericTableAsync(ctx, 0);
93 
94  var resp = await ctx.Kinetica.AggregateUniqueAsync(tableName, "category", 0, -9999, new Dictionary<string, string>());
95 
96  // Empty table returns empty data
97  Assert.Empty(resp.data);
98  }
99 
100  // ============================================================================
101  // AGGREGATE MIN/MAX TESTS
102  // ============================================================================
103 
104  [Fact]
105  public async Task TestAggregateMinMaxBasicAsync()
106  {
107  using var ctx = new TestContext("async_agg_minmax_basic");
108  var tableName = await SetupNumericTableAsync(ctx, 100);
109 
110  var resp = await ctx.Kinetica.AggregateMinMaxAsync(tableName, "id", new Dictionary<string, string>());
111 
112  Assert.Equal(0.0, resp.min);
113  Assert.Equal(99.0, resp.max);
114  }
115 
116  [Fact]
118  {
119  using var ctx = new TestContext("async_agg_minmax_double");
120  var tableName = await SetupNumericTableAsync(ctx, 100);
121 
122  var resp = await ctx.Kinetica.AggregateMinMaxAsync(tableName, "value", new Dictionary<string, string>());
123 
124  // value = id * 1.5, so min = 0.0, max = 99 * 1.5 = 148.5
125  Assert.Equal(0.0, resp.min);
126  Assert.Equal(148.5, resp.max);
127  }
128 
129  [Fact]
131  {
132  using var ctx = new TestContext("async_agg_minmax_single");
133  var tableName = await SetupNumericTableAsync(ctx, 1);
134 
135  var resp = await ctx.Kinetica.AggregateMinMaxAsync(tableName, "id", new Dictionary<string, string>());
136 
137  Assert.Equal(0.0, resp.min);
138  Assert.Equal(0.0, resp.max);
139  }
140 
141  // ============================================================================
142  // AGGREGATE HISTOGRAM TESTS
143  // ============================================================================
144 
145  [Fact]
147  {
148  using var ctx = new TestContext("async_agg_hist_basic");
149  var tableName = await SetupNumericTableAsync(ctx, 100);
150 
151  // Create histogram with 10 bins over range 0-99
152  var resp = await ctx.Kinetica.AggregateHistogramAsync(tableName, "id", 0.0, 100.0, 10.0, new Dictionary<string, string>());
153 
154  Assert.Equal(10, resp.counts.Count); // Should have 10 bins
155  // Each bin should have approximately 10 values
156  foreach (var count in resp.counts)
157  {
158  Assert.True(count >= 9.0 && count <= 11.0); // Allow some tolerance
159  }
160  }
161 
162  [Fact]
164  {
165  using var ctx = new TestContext("async_agg_hist_uneven");
166  var tableName = await SetupNumericTableAsync(ctx, 50);
167 
168  // Create histogram on score column (values 0-9 repeating)
169  var resp = await ctx.Kinetica.AggregateHistogramAsync(tableName, "score", 0.0, 10.0, 2.0, new Dictionary<string, string>());
170 
171  Assert.Equal(5, resp.counts.Count); // Should have 5 bins
172  Assert.Equal(0.0, resp.start);
173  Assert.Equal(10.0, resp.end);
174  }
175 
176  [Fact]
178  {
179  using var ctx = new TestContext("async_agg_hist_empty");
180  var tableName = await SetupNumericTableAsync(ctx, 0);
181 
182  var resp = await ctx.Kinetica.AggregateHistogramAsync(tableName, "id", 0.0, 100.0, 10.0, new Dictionary<string, string>());
183 
184  // All bins should be empty
185  foreach (var count in resp.counts)
186  {
187  Assert.Equal(0.0, count);
188  }
189  }
190 
191  [Fact]
193  {
194  using var ctx = new TestContext("async_agg_hist_single");
195  var tableName = await SetupNumericTableAsync(ctx, 100);
196 
197  // Create histogram with single bin covering all data
198  var resp = await ctx.Kinetica.AggregateHistogramAsync(tableName, "id", 0.0, 100.0, 100.0, new Dictionary<string, string>());
199 
200  Assert.Single(resp.counts);
201  Assert.Equal(100.0, resp.counts[0]); // All records in one bin
202  }
203 
204  // ============================================================================
205  // AGGREGATE STATISTICS TESTS
206  // ============================================================================
207 
208  [Fact]
210  {
211  using var ctx = new TestContext("async_agg_stats_basic");
212  var tableName = await SetupNumericTableAsync(ctx, 100);
213 
214  var resp = await ctx.Kinetica.AggregateStatisticsAsync(tableName, "id", "mean,stdv,count", new Dictionary<string, string>());
215 
216  // For 0-99: mean = 49.5, count = 100
217  Assert.True(Math.Abs(resp.stats["mean"] - 49.5) < 0.1);
218  Assert.Equal(100.0, resp.stats["count"]);
219  Assert.True(resp.stats.ContainsKey("stdv"));
220  }
221 
222  [Fact]
224  {
225  using var ctx = new TestContext("async_agg_stats_all");
226  var tableName = await SetupNumericTableAsync(ctx, 100);
227 
228  var resp = await ctx.Kinetica.AggregateStatisticsAsync(tableName, "value", "mean,stdv,variance,skew,kurtosis,sum", new Dictionary<string, string>());
229 
230  Assert.True(resp.stats.ContainsKey("mean"));
231  Assert.True(resp.stats.ContainsKey("stdv"));
232  Assert.True(resp.stats.ContainsKey("variance"));
233  Assert.True(resp.stats.ContainsKey("sum"));
234  }
235 
236  [Fact]
238  {
239  using var ctx = new TestContext("async_agg_stats_empty");
240  var tableName = await SetupNumericTableAsync(ctx, 0);
241 
242  var resp = await ctx.Kinetica.AggregateStatisticsAsync(tableName, "id", "mean,count", new Dictionary<string, string>());
243 
244  Assert.Equal(0.0, resp.stats["count"]);
245  }
246 
247  // ============================================================================
248  // AGGREGATE GROUP BY TESTS
249  // ============================================================================
250 
251  [Fact]
252  public async Task TestAggregateGroupByCountAsync()
253  {
254  using var ctx = new TestContext("async_agg_groupby_count");
255  var tableName = await SetupNumericTableAsync(ctx, 30);
256 
257  // Group by category and count
258  var resp = await ctx.Kinetica.AggregateGroupByAsync(tableName, new List<string> { "category" }, 0, -9999, new Dictionary<string, string>());
259 
260  // Should have 3 groups (A, B, C)
261  Assert.Equal(3, resp.total_number_of_records);
262  Assert.Equal(3, resp.data.Count);
263  }
264 
265  [Fact]
267  {
268  using var ctx = new TestContext("async_agg_groupby_agg");
269  var tableName = await SetupNumericTableAsync(ctx, 30);
270 
271  // Group by category
272  var resp = await ctx.Kinetica.AggregateGroupByAsync(tableName, new List<string> { "category" }, 0, -9999, new Dictionary<string, string>());
273 
274  // 3 categories
275  Assert.Equal(3, resp.data.Count);
276  }
277 
278  [Fact]
280  {
281  using var ctx = new TestContext("async_agg_groupby_multi");
282 
283  // Create table with more grouping dimensions
284  var tableName = ctx.QualifiedTable("multi_group_table");
285  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT NOT NULL, cat1 VARCHAR(16), cat2 VARCHAR(16), value DOUBLE, PRIMARY KEY (id))");
286 
287  // Insert test data
288  for (int i = 0; i < 20; i++)
289  {
290  var cat1 = i < 10 ? "X" : "Y";
291  var cat2 = (i % 2) == 0 ? "P" : "Q";
292  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} (id, cat1, cat2, value) VALUES ({i}, '{cat1}', '{cat2}', {(double)i})");
293  }
294 
295  // Group by both columns
296  var resp = await ctx.Kinetica.AggregateGroupByAsync(tableName, new List<string> { "cat1", "cat2" }, 0, -9999, new Dictionary<string, string>());
297 
298  // Should have 4 groups: (X,P), (X,Q), (Y,P), (Y,Q)
299  Assert.Equal(4, resp.data.Count);
300  }
301 
302  [Fact]
304  {
305  using var ctx = new TestContext("async_agg_groupby_empty");
306  var tableName = await SetupNumericTableAsync(ctx, 0);
307 
308  var resp = await ctx.Kinetica.AggregateGroupByAsync(tableName, new List<string> { "category" }, 0, -9999, new Dictionary<string, string>());
309 
310  // Empty table returns empty data
311  Assert.Empty(resp.data);
312  }
313 
314  [Fact]
316  {
317  using var ctx = new TestContext("async_agg_groupby_limit");
318  var tableName = await SetupNumericTableAsync(ctx, 30);
319 
320  // Group by category with limit
321  var resp = await ctx.Kinetica.AggregateGroupByAsync(tableName, new List<string> { "category" }, 0, 2, new Dictionary<string, string>());
322 
323  // Limited to 2 groups
324  Assert.Equal(2, resp.data.Count);
325  }
326  }
327 }
Test context that manages schema and cleanup for integration tests.
Definition: TestContext.cs:11
string QualifiedTable(string tableName)
Get a qualified table name (schema.table).
Definition: TestContext.cs:74