public void GetDatasetResults_Success() { var timeframe = QueryRelativeTimeframe.ThisNMinutes(12); var result = new JObject(); var client = new KeenClient(SettingsEnv); Mock <IDataset> datasetMock = null; if (UseMocks) { datasetMock = new Mock <IDataset>(); datasetMock.Setup(m => m.GetResultsAsync( It.Is <string>(n => n == _datasetName), It.Is <string>(i => i == _indexBy), It.Is <string>(t => t == timeframe.ToString()))) .ReturnsAsync(result); client.Datasets = datasetMock.Object; } var dataset = client.QueryDataset(_datasetName, _indexBy, timeframe.ToString()); Assert.IsNotNull(dataset); datasetMock?.VerifyAll(); }
public async Task DefaultHeaders_Success() { object responseData = new[] { new { result = 2 } }; var handler = new FuncHandler() { PreProcess = (req, ct) => { // Make sure the default headers are in place Assert.IsTrue(req.Headers.Contains("Keen-Sdk")); Assert.AreEqual(KeenUtil.GetSdkVersion(), req.Headers.GetValues("Keen-Sdk").Single()); Assert.IsTrue(req.Headers.Contains("Authorization")); var key = req.Headers.GetValues("Authorization").Single(); Assert.IsTrue(SettingsEnv.ReadKey == key || SettingsEnv.WriteKey == key || SettingsEnv.MasterKey == key); }, ProduceResultAsync = (req, ct) => { return(CreateJsonStringResponseAsync(responseData)); }, DeferToDefault = false }; var client = new KeenClient(SettingsEnv, new TestKeenHttpClientProvider() { ProvideKeenHttpClient = (url) => KeenHttpClientFactory.Create(url, new HttpClientCache(), null, new DelegatingHandlerMock(handler)) }); // Try out all the endpoints Assert.DoesNotThrow(() => client.GetSchemas()); // Remaining operations expect an object, not an array of objects responseData = new { result = 2 }; var @event = new { AProperty = "AValue" }; Assert.DoesNotThrow(() => client.AddEvent("AddEventTest", @event)); Assert.DoesNotThrow(() => client.AddEvents("AddEventTest", new[] { @event })); Assert.DoesNotThrow(() => client.DeleteCollection("DeleteColTest")); Assert.IsNotNull(client.GetSchema("AddEventTest")); // Currently all the queries/extraction go through the same KeenWebApiRequest() call. var count = await client.QueryAsync( QueryType.Count(), "testCollection", "", QueryRelativeTimeframe.ThisMonth()); Assert.IsNotNull(count); Assert.AreEqual("2", count); }
public async Task QueryFilter_NotContains_Success() { var queriesUrl = HttpTests.GetUriForResource(SettingsEnv, KeenConstants.QueriesResource); var handler = new FuncHandler() { PreProcess = (req, ct) => { var queryStr = req.RequestUri.Query; // Make sure our filter properties are in the query string Assert.IsTrue(queryStr.Contains("propertyName") && queryStr.Contains("four") && queryStr.Contains(QueryFilter.FilterOperator.NotContains())); }, ProduceResultAsync = (req, ct) => { return(HttpTests.CreateJsonStringResponseAsync(new { result = 2 })); }, DeferToDefault = false }; // NOTE : This example shows use of UrlToMessageHandler, but since we only make one // request to a single endpoint, we could just directly use the FuncHandler here. var urlHandler = new UrlToMessageHandler( new Dictionary <Uri, IHttpMessageHandler> { { queriesUrl, handler } }) { DeferToDefault = false }; var client = new KeenClient(SettingsEnv, new TestKeenHttpClientProvider() { ProvideKeenHttpClient = (url) => KeenHttpClientFactory.Create(url, new HttpClientCache(), null, new DelegatingHandlerMock(urlHandler)) }); var filters = new List <QueryFilter> { new QueryFilter("propertyName", QueryFilter.FilterOperator.NotContains(), "four") }; var count = await client.QueryAsync( QueryType.Count(), "testCollection", "", QueryRelativeTimeframe.ThisMonth(), filters); Assert.IsNotNull(count); Assert.AreEqual("2", count); }
public void Test_TimeframeConverter_Serializes() { var timeframeString = "this_4_hours"; var timeframe = QueryRelativeTimeframe.Create(timeframeString); string json = JsonConvert.SerializeObject(timeframe); Assert.AreEqual($"\"{timeframeString}\"", json); }
public async Task Query_SimpleExtraction_Success() { var queryParameters = new ExtractionParameters() { Timeframe = QueryRelativeTimeframe.ThisNHours(2), }; string resultsJson = @"[ { ""keen"": { ""created_at"": ""2012-07-30T21:21:46.566000+00:00"", ""timestamp"": ""2012-07-30T21:21:46.566000+00:00"", ""id"": """" }, ""user"": { ""email"": ""*****@*****.**"", ""id"": ""4f4db6c7777d66ffff000000"" }, ""user_agent"": { ""browser"": ""chrome"", ""browser_version"": ""20.0.1132.57"", ""platform"": ""macos"" } }, { ""keen"": { ""created_at"": ""2012-07-30T21:40:05.386000+00:00"", ""timestamp"": ""2012-07-30T21:40:05.386000+00:00"", ""id"": """" }, ""user"": { ""email"": ""*****@*****.**"", ""id"": ""4fa2cccccf546ffff000006"" }, ""user_agent"": { ""browser"": ""chrome"", ""browser_version"": ""20.0.1132.57"", ""platform"": ""macos"" } } ]"; var expectedResults = JArray.Parse(resultsJson); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Extract( queryParameters.EventCollection, queryParameters.Timeframe); Assert.That(actualResults, Is.EquivalentTo(expectedResults)); }
public async Task Query_SimpleSelectUniqueInterval_Success() { var queryParameters = new QueryParameters() { Analysis = QueryType.SelectUnique(), TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1) }; var expectedCounts = new List <string[]>() { new string[] { "10", "20" }, new string[] { "30", "40" } }; var expectedTimeframes = new List <QueryAbsoluteTimeframe>() { new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-2), DateTime.Now.AddHours(-1)), new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-1), DateTime.Now) }; var expectedResults = expectedCounts.Zip( expectedTimeframes, (count, time) => new { timeframe = time, value = count }); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.Timeframe, queryParameters.Interval); Assert.AreEqual(expectedResults.Count(), actualResults.Count()); var expectedEnumerator = expectedResults.GetEnumerator(); var actualEnumerator = actualResults.GetEnumerator(); while (expectedEnumerator.MoveNext() && actualEnumerator.MoveNext()) { var expected = expectedEnumerator.Current; var actual = actualEnumerator.Current; Assert.AreEqual(expected.timeframe.Start, actual.Start); Assert.AreEqual(expected.timeframe.End, actual.End); Assert.AreEqual(string.Join(",", expected.value), actual.Value); } }
public async Task QueryFilter_NullPropertyValue_Success() { // TODO : Consolidate this FuncHandler/KeenClient setup into a helper method. var handler = new FuncHandler() { PreProcess = (req, ct) => { var queryStr = req.RequestUri.Query; // Make sure our filter properties are in the query string Assert.IsTrue(queryStr.Contains("propertyName") && queryStr.Contains("null") && queryStr.Contains(QueryFilter.FilterOperator.Equals())); }, ProduceResultAsync = (req, ct) => { return(HttpTests.CreateJsonStringResponseAsync(new { result = 2 })); }, DeferToDefault = false }; var client = new KeenClient(SettingsEnv, new TestKeenHttpClientProvider() { ProvideKeenHttpClient = (url) => KeenHttpClientFactory.Create(url, new HttpClientCache(), null, new DelegatingHandlerMock(handler)) }); var filters = new List <QueryFilter> { new QueryFilter("propertyName", QueryFilter.FilterOperator.Equals(), null) }; var count = await client.QueryAsync( QueryType.Count(), "testCollection", "", QueryRelativeTimeframe.ThisMonth(), filters); Assert.IsNotNull(count); Assert.AreEqual("2", count); }
public async Task Query_SimpleSelectUniqueInterval_Success() { var queryParameters = new QueryParameters() { Analysis = QueryType.SelectUnique(), TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1) }; var expectedCounts = new List <string[]>() { new string[] { "10", "20" }, new string[] { "30", "40" } }; var expectedTimeframes = new List <QueryAbsoluteTimeframe>() { new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-2), DateTime.Now.AddHours(-1)), new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-1), DateTime.Now) }; var expectedResults = expectedCounts.Zip( expectedTimeframes, (count, time) => new { timeframe = time, value = count }); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResult = await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.Timeframe, queryParameters.Interval); var expectedSdkResult = expectedResults.Select((result) => { return(new QueryIntervalValue <string>( string.Join(',', result.value), result.timeframe.Start, result.timeframe.End)); }); Assert.That(actualResult, Is.EquivalentTo(expectedSdkResult)); }
public async Task Query_SimpleFunnel_Success() { var queryParameters = new FunnelParameters() { Steps = new FunnelStep[] { new FunnelStep() { EventCollection = "signed up", ActorProperty = "visitor.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, new FunnelStep() { EventCollection = "completed profile", ActorProperty = "user.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, new FunnelStep() { EventCollection = "referred user", ActorProperty = "user.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, } }; string responseJson = @"{ ""result"": [ 3, 1, 0 ], ""steps"": [ { ""actor_property"": ""visitor.guid"", ""event_collection"": ""signed up"", ""timeframe"": ""this_7_days"" }, { ""actor_property"": ""user.guid"", ""event_collection"": ""completed profile"", ""timeframe"": ""this_7_days"" }, { ""actor_property"": ""user.guid"", ""event_collection"": ""referred user"", ""timeframe"": ""this_7_days"" } ] }"; var expectedResponse = JObject.Parse(responseJson); var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Funnel( queryParameters.Steps); var expectedResults = expectedResponse["result"].Values <int>(); Assert.That(actualResults.Result, Is.EquivalentTo(expectedResults)); var expectedSteps = queryParameters.Steps.Select((step) => new FunnelResultStep() { EventCollection = step.EventCollection, ActorProperty = step.ActorProperty, Timeframe = step.Timeframe }); Assert.That(actualResults.Steps, Is.EquivalentTo(expectedSteps)); }
public async Task Query_SimpleSelectUniqueGroupByInterval_Success() { var queryParameters = new QueryParameters() { Analysis = QueryType.SelectUnique(), TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1), GroupBy = "someGroupProperty" }; string resultsJson = @"[ { ""timeframe"": { ""start"": ""2017-10-14T00:00:00.000Z"", ""end"": ""2017-10-15T00:00:00.000Z"" }, ""value"": [ { ""someGroupProperty"": ""group1"", ""result"": [ ""10"", ""20"" ] }, { ""someGroupProperty"": ""group2"", ""result"": [ ""30"", ""40"" ] } ] }, { ""timeframe"": { ""start"": ""2017-10-15T00:00:00.000Z"", ""end"": ""2017-10-16T00:00:00.000Z"" }, ""value"": [ { ""someGroupProperty"": ""group1"", ""result"": [ ""50"", ""60"" ] }, { ""someGroupProperty"": ""group2"", ""result"": [ ""70"", ""80"" ] } ] } ]"; var expectedResults = JArray.Parse(resultsJson); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResult = await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.GroupBy, queryParameters.Timeframe, queryParameters.Interval); var expectedSdkResult = expectedResults.Select((intervalToken) => { return(new QueryIntervalValue <IEnumerable <QueryGroupValue <string> > >( intervalToken["value"].Select((groupToken) => { return new QueryGroupValue <string>( string.Join(',', groupToken["result"]), groupToken[queryParameters.GroupBy].Value <string>()); }), intervalToken["timeframe"]["start"].Value <DateTime>(), intervalToken["timeframe"]["end"].Value <DateTime>())); }); // Use JArray objects as a way to normalize types here, since the // concrete types won't match for the QueryInternalValue IEnumerable implementation. Assert.That(JArray.FromObject(actualResult), Is.EquivalentTo(JArray.FromObject(expectedSdkResult))); }
public async Task Query_SimpleCountGroupByInterval_Success() { var queryParameters = new QueryParameters() { TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1), GroupBy = "someGroupProperty" }; var expectedResults = new[] { new { timeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-2), DateTime.Now.AddHours(-1)), value = new List <Dictionary <string, string> > { new Dictionary <string, string> { { queryParameters.GroupBy, "group1" }, { "result", "10" } }, new Dictionary <string, string> { { queryParameters.GroupBy, "group2" }, { "result", "20" } }, } }, new { timeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-1), DateTime.Now), value = new List <Dictionary <string, string> > { new Dictionary <string, string> { { queryParameters.GroupBy, "group1" }, { "result", "30" } }, new Dictionary <string, string> { { queryParameters.GroupBy, "group2" }, { "result", "40" } }, } } }; var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResult = (await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.GroupBy, queryParameters.Timeframe, queryParameters.Interval)); var expectedSdkResult = expectedResults.Select((intervals) => { return(new QueryIntervalValue <IEnumerable <QueryGroupValue <string> > >( intervals.value.Select((group) => new QueryGroupValue <string>( group["result"], group[queryParameters.GroupBy])), intervals.timeframe.Start, intervals.timeframe.End )); }); // Use JArray objects as a way to normalize types here, since the // concrete types won't match for the QueryInternalValue IEnumerable implementation. Assert.That(JArray.FromObject(actualResult), Is.EquivalentTo(JArray.FromObject(expectedSdkResult))); }
public async Task Funnel_Simple_Success() { var client = new KeenClient(SettingsEnv); var timeframe = QueryRelativeTimeframe.ThisHour(); IEnumerable <FunnelStep> funnelsteps = new List <FunnelStep> { new FunnelStep { EventCollection = FunnelColA, ActorProperty = "id", }, new FunnelStep { EventCollection = FunnelColB, ActorProperty = "id" }, }; var expected = new FunnelResult { Steps = new[] { new FunnelResultStep { EventCollection = FunnelColA, }, new FunnelResultStep { EventCollection = FunnelColB, }, }, Result = new[] { 3, 2 } }; Mock <IQueries> queryMock = null; if (UseMocks) { queryMock = new Mock <IQueries>(); queryMock.Setup(m => m.Funnel( It.Is <IEnumerable <FunnelStep> >(f => f.Equals(funnelsteps)), It.Is <IQueryTimeframe>(t => t == timeframe), It.Is <string>(t => t == "") )) .Returns(Task.FromResult(expected)); client.Queries = queryMock.Object; } var reply = (await client.QueryFunnelAsync(funnelsteps, timeframe)); Assert.NotNull(reply); Assert.NotNull(reply.Result); Assert.NotNull(reply.Steps); Assert.AreEqual(reply.Steps.Count(), 2); if (null != queryMock) { queryMock.VerifyAll(); } }
public async Task Funnel_ValidTimeframeInSteps_Success() { var client = new KeenClient(SettingsEnv); IEnumerable <FunnelStep> funnelsteps = new[] { new FunnelStep { EventCollection = FunnelColA, ActorProperty = "id", Timeframe = QueryRelativeTimeframe.ThisMonth(), }, new FunnelStep { EventCollection = FunnelColB, ActorProperty = "id", Timeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddDays(-30), DateTime.Now), }, }; var expected = new FunnelResult { Steps = new[] { new FunnelResultStep { EventCollection = FunnelColA, }, new FunnelResultStep { EventCollection = FunnelColB, }, }, Result = new[] { 3, 2 } }; Mock <IQueries> queryMock = null; if (UseMocks) { queryMock = new Mock <IQueries>(); queryMock.Setup(m => m.Funnel( It.Is <IEnumerable <FunnelStep> >(f => f.Equals(funnelsteps)), It.Is <IQueryTimeframe>(t => null == t), It.Is <string>(t => t == "") )) .Returns(Task.FromResult(expected)); client.Queries = queryMock.Object; } var reply = (await client.QueryFunnelAsync(funnelsteps, null)); Assert.NotNull(reply); Assert.NotNull(reply.Result); Assert.True(reply.Result.SequenceEqual(expected.Result)); Assert.NotNull(reply.Steps); Assert.AreEqual(reply.Steps.Count(), 2); if (null != queryMock) { queryMock.VerifyAll(); } }
public async Task Query_SimpleFunnel_Success() { var queryParameters = new FunnelParameters() { Steps = new FunnelStep[] { new FunnelStep() { EventCollection = "signed up", ActorProperty = "visitor.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, new FunnelStep() { EventCollection = "completed profile", ActorProperty = "user.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, new FunnelStep() { EventCollection = "referred user", ActorProperty = "user.guid", Timeframe = QueryRelativeTimeframe.ThisNDays(7) }, } }; string responseJson = @"{ ""result"": [ 3, 1, 0 ], ""steps"": [ { ""actor_property"": ""visitor.guid"", ""event_collection"": ""signed up"", ""timeframe"": ""this_7_days"" }, { ""actor_property"": ""user.guid"", ""event_collection"": ""completed profile"", ""timeframe"": ""this_7_days"" }, { ""actor_property"": ""user.guid"", ""event_collection"": ""referred user"", ""timeframe"": ""this_7_days"" } ] }"; var expectedResponse = JObject.Parse(responseJson); var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Funnel( queryParameters.Steps); var expectedResults = expectedResponse["result"]; Assert.AreEqual(expectedResults.Count(), actualResults.Result.Count()); var actualEnumerator = actualResults.Result.GetEnumerator(); foreach (var expected in expectedResults) { actualEnumerator.MoveNext(); var actual = actualEnumerator.Current; // Validate the result is correct Assert.AreEqual(expected.Value <int>(), actual); } }
public async Task Query_SimpleExtraction_Success() { var queryParameters = new ExtractionParameters() { Timeframe = QueryRelativeTimeframe.ThisNHours(2), }; string resultsJson = @"[ { ""keen"": { ""created_at"": ""2012-07-30T21:21:46.566000+00:00"", ""timestamp"": ""2012-07-30T21:21:46.566000+00:00"", ""id"": """" }, ""user"": { ""email"": ""*****@*****.**"", ""id"": ""4f4db6c7777d66ffff000000"" }, ""user_agent"": { ""browser"": ""chrome"", ""browser_version"": ""20.0.1132.57"", ""platform"": ""macos"" } }, { ""keen"": { ""created_at"": ""2012-07-30T21:40:05.386000+00:00"", ""timestamp"": ""2012-07-30T21:40:05.386000+00:00"", ""id"": """" }, ""user"": { ""email"": ""*****@*****.**"", ""id"": ""4fa2cccccf546ffff000006"" }, ""user_agent"": { ""browser"": ""chrome"", ""browser_version"": ""20.0.1132.57"", ""platform"": ""macos"" } } ]"; var expectedResults = JArray.Parse(resultsJson); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Extract( queryParameters.EventCollection, queryParameters.Timeframe); Assert.AreEqual(expectedResults.Count(), actualResults.Count()); var actualEnumerator = actualResults.GetEnumerator(); foreach (var expected in expectedResults) { actualEnumerator.MoveNext(); JToken actual = actualEnumerator.Current; // Validate the result is correct Assert.AreEqual(expected["user"]["email"].Value <string>(), actual["user"]["email"].Value <string>()); Assert.AreEqual(expected["user"]["id"].Value <string>(), actual["user"]["id"].Value <string>()); Assert.AreEqual(expected["user_agent"]["browser"].Value <string>(), actual["user_agent"]["browser"].Value <string>()); } }
public async Task Query_SimpleSelectUniqueGroupByInterval_Success() { var queryParameters = new QueryParameters() { Analysis = QueryType.SelectUnique(), TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1), GroupBy = "someGroupProperty" }; string resultsJson = @"[ { ""timeframe"": { ""start"": ""2017-10-14T00:00:00.000Z"", ""end"": ""2017-10-15T00:00:00.000Z"" }, ""value"": [ { ""someGroupProperty"": ""group1"", ""result"": [ ""10"", ""20"" ] }, { ""someGroupProperty"": ""group2"", ""result"": [ ""30"", ""40"" ] } ] }, { ""timeframe"": { ""start"": ""2017-10-15T00:00:00.000Z"", ""end"": ""2017-10-16T00:00:00.000Z"" }, ""value"": [ { ""someGroupProperty"": ""group1"", ""result"": [ ""50"", ""60"" ] }, { ""someGroupProperty"": ""group2"", ""result"": [ ""70"", ""80"" ] } ] } ]"; var expectedResults = JArray.Parse(resultsJson); var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.GroupBy, queryParameters.Timeframe, queryParameters.Interval); Assert.AreEqual(expectedResults.Count(), actualResults.Count()); var actualEnumerator = actualResults.GetEnumerator(); foreach (var expected in expectedResults) { actualEnumerator.MoveNext(); var actual = actualEnumerator.Current; // Validate the interval is correct Assert.AreEqual(DateTime.Parse(expected["timeframe"]["start"].Value <string>()), actual.Start); Assert.AreEqual(DateTime.Parse(expected["timeframe"]["end"].Value <string>()), actual.End); // Validate the results for the group within the time interval Assert.AreEqual(expected["value"].Count(), actual.Value.Count()); var actualGroupResultEnumerator = actual.Value.GetEnumerator(); foreach (var expectedGroupResult in expected["value"]) { actualGroupResultEnumerator.MoveNext(); var actualGroupResult = actualGroupResultEnumerator.Current; Assert.AreEqual(expectedGroupResult[queryParameters.GroupBy].Value <string>(), actualGroupResult.Group); Assert.AreEqual(string.Join(",", expectedGroupResult["result"].Values <string>()), actualGroupResult.Value); } } }
public async Task Query_SimpleCountGroupByInterval_Success() { var queryParameters = new QueryParameters() { TargetProperty = "someProperty", Timeframe = QueryRelativeTimeframe.ThisNHours(2), Interval = QueryInterval.EveryNHours(1), GroupBy = "someGroupProperty" }; var expectedResults = new[] { new { timeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-2), DateTime.Now.AddHours(-1)), value = new List <Dictionary <string, string> > { new Dictionary <string, string> { { queryParameters.GroupBy, "group1" }, { "result", "10" } }, new Dictionary <string, string> { { queryParameters.GroupBy, "group2" }, { "result", "20" } }, } }, new { timeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddHours(-1), DateTime.Now), value = new List <Dictionary <string, string> > { new Dictionary <string, string> { { queryParameters.GroupBy, "group1" }, { "result", "30" } }, new Dictionary <string, string> { { queryParameters.GroupBy, "group2" }, { "result", "40" } }, } } }; var expectedResponse = new { result = expectedResults }; var client = CreateQueryTestKeenClient(queryParameters, expectedResponse); var actualResults = await client.Queries.Metric( queryParameters.Analysis, queryParameters.EventCollection, queryParameters.TargetProperty, queryParameters.GroupBy, queryParameters.Timeframe, queryParameters.Interval); Assert.AreEqual(expectedResults.Count(), actualResults.Count()); var actualEnumerator = actualResults.GetEnumerator(); foreach (var expected in expectedResults) { actualEnumerator.MoveNext(); var actual = actualEnumerator.Current; // Validate the interval is correct Assert.AreEqual(expected.timeframe.Start, actual.Start); Assert.AreEqual(expected.timeframe.End, actual.End); // Validate the results for the group within the time interval Assert.AreEqual(expected.value.Count, actual.Value.Count()); var actualGroupResultEnumerator = actual.Value.GetEnumerator(); foreach (var expectedGroupResult in expected.value) { actualGroupResultEnumerator.MoveNext(); var actualGroupResult = actualGroupResultEnumerator.Current; Assert.AreEqual(expectedGroupResult[queryParameters.GroupBy], actualGroupResult.Group); Assert.AreEqual(expectedGroupResult["result"], actualGroupResult.Value); } } }