From 6e4f75854a6b4e37cd9e3f36abd9960a0ad28dc1 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Fri, 25 Jan 2013 15:05:05 -0600 Subject: [PATCH 01/20] Add a Segment class to handle a segment of datapoints and the next link --- Client.Tests/Client.Tests.csproj | 1 + Client.Tests/CursorTests.cs | 44 ++++++++++++++++ Client/Cursor.cs | 89 ++++++++++++++++++++++++++++++++ Client/TempoClient.csproj | 1 + 4 files changed, 135 insertions(+) create mode 100644 Client.Tests/CursorTests.cs create mode 100644 Client/Cursor.cs diff --git a/Client.Tests/Client.Tests.csproj b/Client.Tests/Client.Tests.csproj index db984fc..3598b10 100644 --- a/Client.Tests/Client.Tests.csproj +++ b/Client.Tests/Client.Tests.csproj @@ -52,6 +52,7 @@ + diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs new file mode 100644 index 0000000..27f7a7b --- /dev/null +++ b/Client.Tests/CursorTests.cs @@ -0,0 +1,44 @@ +using Client; +using Client.Model; +using NUnit.Framework; +using System; +using System.Collections.Generic; + + +namespace Client.Tests +{ + [TestFixture] + public class SegmentTests + { + [Test] + public void Constructor() + { + List data = new List { new DataPoint(new DateTime(2012, 3, 27), 12.34) }; + Segment segment = new Segment(data, "next"); + Assert.AreEqual(data, segment.Data); + Assert.AreEqual("next", segment.NextUrl); + } + + [Test] + public void Deserialize() + { + string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}]"; + RestSharp.RestResponse response = new RestSharp.RestResponse + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + RestSharp.Parameter link = new RestSharp.Parameter + { + Name = "Link", + Value = "; rel=\"next\"" + }; + response.Headers.Add(link); + + Segment segment = new Segment(response); + Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); + Assert.AreEqual(expected.Data, segment.Data); + Assert.AreEqual(expected.NextUrl, segment.NextUrl); + } + } +} diff --git a/Client/Cursor.cs b/Client/Cursor.cs new file mode 100644 index 0000000..8b06882 --- /dev/null +++ b/Client/Cursor.cs @@ -0,0 +1,89 @@ +using Client.Model; +using RestSharp; +using RestSharp.Deserializers; +using System; +using System.Collections.Generic; + + +namespace Client +{ + public class Segment + { + public IList Data { get; set; } + public string NextUrl { get; set; } + + public Segment(IList data, string next) + { + Data = data; + NextUrl = next; + } + + /// For now, build the Segment by passing in a RestResponse. + /// This should be handled by a deserializer in the future + public Segment(IRestResponse response) + { + /// Deserialize the data + JsonDeserializer deserializer = new JsonDeserializer(); + List data = deserializer.Deserialize>(response); + Data = data; + + /// Get the next link from the Link header + Parameter header = null; + foreach(Parameter h in response.Headers) + { + if(h.Name.ToLower().Equals("link")) + { + header = h; + break; + } + } + + Dictionary> links = new Dictionary>(); + if(header != null) + { + List> l = ParseHeaderLinks(header.Value as string); + foreach(Dictionary link in l) + { + string key = link.ContainsKey("rel") ? link["rel"] : link["url"]; + links.Add(key, link); + } + } + + Dictionary next = new Dictionary(); + string nextUrl = null; + if(links.TryGetValue("next", out next)) + { + next.TryGetValue("url", out nextUrl); + } + NextUrl = nextUrl; + } + + private List> ParseHeaderLinks(string header) + { + char[] replaceChars = {' ', '\'', '"'}; + char[] replaceUrlChars = {'<', '>', ' ', '\'', '"'}; + List> links = new List>(); + foreach(string val in header.Split(',')) + { + string[] items = val.Split(';'); + if(items.Length > 0) + { + string url = items[0]; + string parameters = items.Length > 1 ? items[1] : ""; + Dictionary link = new Dictionary(); + link.Add("url", url.Trim(replaceUrlChars)); + foreach(string param in parameters.Split(';')) + { + string[] keys = param.Split('='); + if(keys.Length < 1) break; + string key = keys[0]; + string item = keys[1]; + link.Add(key.Trim(replaceChars).ToLower(), item.Trim(replaceChars)); + } + links.Add(link); + } + } + return links; + } + } +} diff --git a/Client/TempoClient.csproj b/Client/TempoClient.csproj index b2eaed3..3778663 100644 --- a/Client/TempoClient.csproj +++ b/Client/TempoClient.csproj @@ -49,6 +49,7 @@ + From 83ce631700d3151155c6a4fe64527bb66bc9cf75 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Fri, 25 Jan 2013 16:06:16 -0600 Subject: [PATCH 02/20] Make the Segment an iterator of DataPoints --- Client.Tests/CursorTests.cs | 30 ++++++++++++++++++++++++++---- Client/Cursor.cs | 8 ++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 27f7a7b..91ccc8b 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -23,13 +23,11 @@ public void Constructor() public void Deserialize() { string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}]"; - RestSharp.RestResponse response = new RestSharp.RestResponse - { + RestSharp.RestResponse response = new RestSharp.RestResponse { StatusCode = System.Net.HttpStatusCode.OK, Content = content }; - RestSharp.Parameter link = new RestSharp.Parameter - { + RestSharp.Parameter link = new RestSharp.Parameter { Name = "Link", Value = "; rel=\"next\"" }; @@ -40,5 +38,29 @@ public void Deserialize() Assert.AreEqual(expected.Data, segment.Data); Assert.AreEqual(expected.NextUrl, segment.NextUrl); } + + [Test] + public void Iterator() + { + string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]"; + RestSharp.RestResponse response = new RestSharp.RestResponse + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + + Segment segment = new Segment(response); + List expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) + }; + + List output = new List(); + foreach(DataPoint dp in segment) + { + output.Add(dp); + } + Assert.AreEqual(expected, output); + } } } diff --git a/Client/Cursor.cs b/Client/Cursor.cs index 8b06882..381b829 100644 --- a/Client/Cursor.cs +++ b/Client/Cursor.cs @@ -58,6 +58,14 @@ public Segment(IRestResponse response) NextUrl = nextUrl; } + public IEnumerator GetEnumerator() + { + foreach(DataPoint dp in Data) + { + yield return dp; + } + } + private List> ParseHeaderLinks(string header) { char[] replaceChars = {' ', '\'', '"'}; From 18d6cf4a7fee7b44892793894b8845cd41daf4bd Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Fri, 25 Jan 2013 16:36:01 -0600 Subject: [PATCH 03/20] Add SegmentEnumerator and Cursor classes --- Client/Client.cs | 43 +++++++++++++++++++++---------------------- Client/Cursor.cs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/Client/Client.cs b/Client/Client.cs index 631b2fa..890e717 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -56,7 +56,7 @@ public Client(string key, string secret, string host = "api.tempo-db.com", int p /// Executes the rest request, where no response is expected. /// /// The request to be executed - public void Execute(RestRequest request) + public IRestResponse Execute(RestRequest request) { RestClient client = GetRestClient(); IRestResponse response = client.Execute(request); @@ -66,6 +66,7 @@ public void Execute(RestRequest request) throw new Exception(string.Format("Service call failed with HTTP response [{0}].", Enum.GetName(typeof (HttpStatusCode), response.StatusCode))); } + return response; } /// @@ -96,6 +97,25 @@ public void Execute(RestRequest request) return response.Data; } + public RestRequest BuildRequest(string url, Method method, object body = null) + { + var request = new RestRequest { + Method = method, + Resource = url, + Timeout = DEFAULT_TIMEOUT_MILLIS, + RequestFormat = DataFormat.Json, + JsonSerializer = new JsonSerializer() + }; + request.AddHeader("Accept-Encoding", "gzip,deflate"); + + if (body != null) + { + request.AddBody(body); + } + + return request; + } + private RestClient GetRestClient() { if (_restClient == null) @@ -308,27 +328,6 @@ private void DeleteDataPoints(string seriesProperty, string propertyValue, DateT Execute(request); } - private RestRequest BuildRequest(string url, Method method, object body = null) - { - var request = new RestRequest - { - Method = method, - Resource = url, - Timeout = DEFAULT_TIMEOUT_MILLIS, - RequestFormat = DataFormat.Json, - JsonSerializer = new JsonSerializer() - }; - - request.AddHeader("Accept-Encoding", "gzip,deflate"); - - if (body != null) - { - request.AddBody(body); - } - - return request; - } - /// /// Reads a DataSet by id /// diff --git a/Client/Cursor.cs b/Client/Cursor.cs index 381b829..e4e382a 100644 --- a/Client/Cursor.cs +++ b/Client/Cursor.cs @@ -7,6 +7,51 @@ namespace Client { + public class Cursor + { + private SegmentEnumerator segments; + + public Cursor(SegmentEnumerator segments) + { + this.segments = segments; + } + + public IEnumerator GetEnumerator() + { + foreach(Segment segment in segments) + { + foreach(DataPoint dp in segment) + { + yield return dp; + } + } + } + } + + public class SegmentEnumerator + { + private Segment segment; + private Client client; + + public SegmentEnumerator(Client client, Segment segment) + { + this.client = client; + this.segment = segment; + } + + public IEnumerator GetEnumerator() + { + yield return segment; + while(segment.NextUrl != null) + { + var request = client.BuildRequest(segment.NextUrl, Method.GET); + var response = client.Execute(request); + segment = new Segment(response); + yield return segment; + } + } + } + public class Segment { public IList Data { get; set; } From a22df2436662260c518a3846f8dbf1cf60d4d86a Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Fri, 25 Jan 2013 16:46:56 -0600 Subject: [PATCH 04/20] Move the version setting down into the api calls --- Client.Tests/DeleteTests.cs | 4 ++-- Client.Tests/IncrementTests.cs | 2 +- Client.Tests/ReadTests.cs | 6 ++--- Client.Tests/SeriesTests.cs | 10 ++++---- Client/Client.cs | 44 +++++++++++++++++++--------------- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/Client.Tests/DeleteTests.cs b/Client.Tests/DeleteTests.cs index 8e55d32..c3ae57d 100644 --- a/Client.Tests/DeleteTests.cs +++ b/Client.Tests/DeleteTests.cs @@ -23,7 +23,7 @@ public void SmokeTest() client.DeleteById("series-id", new DateTime(2012, 1, 1), new DateTime(2012, 1, 1, 1, 0, 0)); mockclient.Verify(cl => cl.Execute(It.Is(req => req.Method == Method.DELETE))); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/{property}/{value}/data"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-01-01T00:00:00.000-06:00")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-01-01T01:00:00.000-06:00")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "id")))); @@ -39,7 +39,7 @@ public void Key() client.DeleteByKey("series-key", new DateTime(2012, 1, 1), new DateTime(2012, 1, 1, 1, 0, 0)); mockclient.Verify(cl => cl.Execute(It.Is(req => req.Method == Method.DELETE))); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/{property}/{value}/data"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-01-01T00:00:00.000-06:00")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-01-01T01:00:00.000-06:00")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); diff --git a/Client.Tests/IncrementTests.cs b/Client.Tests/IncrementTests.cs index dd5b736..dec47e6 100644 --- a/Client.Tests/IncrementTests.cs +++ b/Client.Tests/IncrementTests.cs @@ -23,7 +23,7 @@ public void Request() data.Add(new DataPoint(DateTime.Now, valueToAdd)); client.IncrementByKey("key", data); - Expression> assertion = req => req.Method == Method.POST && req.Resource == "/series/{property}/{value}/increment/"; + Expression> assertion = req => req.Method == Method.POST && req.Resource == "/{version}/series/{property}/{value}/increment/"; mockclient.Verify(cl => cl.Execute(It.Is(assertion))); } diff --git a/Client.Tests/ReadTests.cs b/Client.Tests/ReadTests.cs index 6d6976a..67bccad 100644 --- a/Client.Tests/ReadTests.cs +++ b/Client.Tests/ReadTests.cs @@ -83,7 +83,7 @@ public void RequestUrl() client.ReadByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/{property}/{value}/data"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testkey")))); } @@ -108,7 +108,7 @@ public void RequestMethod_Id() client.ReadById("testid", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/{property}/{value}/data"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "id")))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testid")))); } @@ -178,7 +178,7 @@ public void RequestUrl() filter.AddKey("series2"); client.ReadMultipleSeries(new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), filter, IntervalParameter.Raw()); - Expression> assertion = req => req.Resource == "/data/"; + Expression> assertion = req => req.Resource == "/{version}/data/"; mockclient.Verify(cl => cl.Execute>(It.Is(assertion))); } diff --git a/Client.Tests/SeriesTests.cs b/Client.Tests/SeriesTests.cs index fd35a74..072bd65 100644 --- a/Client.Tests/SeriesTests.cs +++ b/Client.Tests/SeriesTests.cs @@ -73,7 +73,7 @@ public void RequestUrl() client.CreateSeries("series-key"); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/"))); } [Test] @@ -138,7 +138,7 @@ public void RequestUrl() client.GetSeriesById("series-id"); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/id/{id}"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/id/{id}"))); } [Test] @@ -198,7 +198,7 @@ public void KeyRequestUrl() client.GetSeriesByKey("series-key"); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/key/{key}"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/key/{key}"))); } [Test] @@ -264,7 +264,7 @@ public void RequestUrl() client.ListSeries(); - mockclient.Verify(cl => cl.Execute>(It.Is(req => req.Resource == "/series"))); + mockclient.Verify(cl => cl.Execute>(It.Is(req => req.Resource == "/{version}/series/"))); } [Test] @@ -348,7 +348,7 @@ public void RequestUrl() client.UpdateSeries(seriesResponse); - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/series/id/{id}/"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/id/{id}/"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "id", "series-id")))); } } diff --git a/Client/Client.cs b/Client/Client.cs index 890e717..f9bfc95 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -123,7 +123,7 @@ private RestClient GetRestClient() string protocol = _secure ? "https://" : "http://"; string portString = (_port == 80) ? "" : ":" + _port; - string baseUrl = protocol + _host + portString + "/" + _version; + string baseUrl = protocol + _host + portString; var client = new RestClient { @@ -147,11 +147,12 @@ private RestClient GetRestClient() /// A Series public Series CreateSeries(string key = "") { - const string url = "/series/"; + const string url = "/{version}/series/"; var body = new Dictionary(); body.Add("key", key); RestRequest request = BuildRequest(url, Method.POST, body); + request.AddUrlSegment("version", _version); return Execute(request); } @@ -162,8 +163,9 @@ public Series CreateSeries(string key = "") /// The updated Series public Series UpdateSeries(Series series) { - const string url = "/series/id/{id}/"; + const string url = "/{version}/series/id/{id}/"; RestRequest request = BuildRequest(url, Method.PUT, series); + request.AddUrlSegment("version", _version); request.AddUrlSegment("id", series.Id); return Execute(request); } @@ -174,11 +176,10 @@ public Series UpdateSeries(Series series) /// A list of Series with the matching Key public Series GetSeriesByKey(string key) { - const string url = "/series/key/{key}"; - + const string url = "/{version}/series/key/{key}"; RestRequest request = BuildRequest(url, Method.GET); + request.AddUrlSegment("version", _version); request.AddUrlSegment("key", key); - return Execute(request); } @@ -188,11 +189,10 @@ public Series GetSeriesByKey(string key) /// The Series that matches the specified Id public Series GetSeriesById(string id) { - const string url = "/series/id/{id}"; - + const string url = "/{version}/series/id/{id}"; RestRequest request = BuildRequest(url, Method.GET); + request.AddUrlSegment("version", _version); request.AddUrlSegment("id", id); - return Execute(request); } @@ -208,8 +208,9 @@ public List ListSeries(Filter filter = null) filter = new Filter(); } - const string url = "/series"; + const string url = "/{version}/series/"; RestRequest request = BuildRequest(url, Method.GET); + request.AddUrlSegment("version", _version); ApplyFilterToRequest(request, filter); var result = Execute>(request); return result; @@ -237,8 +238,9 @@ public void WriteByKey(string seriesKey, IList data) private void WriteDataPoints(string seriesProperty, string propertyValue, IList data) { - const string url = "/series/{property}/{value}/data/"; + const string url = "/{version}/series/{property}/{value}/data/"; RestRequest request = BuildRequest(url, Method.POST, data); + request.AddUrlSegment("version", _version); request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); Execute(request); @@ -250,8 +252,9 @@ private void WriteDataPoints(string seriesProperty, string propertyValue, IList< /// A BulkDataSet to write public virtual void WriteBulkData(BulkDataSet dataSet) { - const string url = "/data/"; + const string url = "/{version}/data/"; RestRequest request = BuildRequest(url, Method.POST, dataSet); + request.AddUrlSegment("version", _version); Execute(request); } @@ -277,8 +280,9 @@ public void IncrementByKey(string seriesKey, IList data) private void IncrementDataPoints(string seriesProperty, string propertyValue, IList data) { - const string url = "/series/{property}/{value}/increment/"; + const string url = "/{version}/series/{property}/{value}/increment/"; RestRequest request = BuildRequest(url, Method.POST, data); + request.AddUrlSegment("version", _version); request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); Execute(request); @@ -290,8 +294,9 @@ private void IncrementDataPoints(string seriesProperty, string propertyValue, IL /// A BulkDataSet to increments public virtual void IncrementBulkData(BulkDataSet dataSet) { - const string url = "/increment/"; + const string url = "/{version}/increment/"; RestRequest request = BuildRequest(url, Method.POST, dataSet); + request.AddUrlSegment("version", _version); Execute(request); } @@ -319,8 +324,9 @@ public void DeleteByKey(string seriesKey, DateTime start, DateTime end) private void DeleteDataPoints(string seriesProperty, string propertyValue, DateTime start, DateTime end) { - const string url = "/series/{property}/{value}/data"; + const string url = "/{version}/series/{property}/{value}/data"; RestRequest request = BuildRequest(url, Method.DELETE); + request.AddUrlSegment("version", _version); request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); request.AddParameter(QueryStringParameter.Start, TempoDateTimeConvertor.ConvertDateTimeToString(start)); @@ -361,8 +367,8 @@ public virtual DataSet ReadByKey(string seriesKey, DateTime start, DateTime end, private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTime start, DateTime end, string interval = null, string function = null) { - RestRequest request = BuildRequest("/series/{property}/{value}/data", Method.GET); - + RestRequest request = BuildRequest("/{version}/series/{property}/{value}/data", Method.GET); + request.AddUrlSegment("version", _version); request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); @@ -384,8 +390,8 @@ private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTim public virtual IList ReadMultipleSeries(DateTime start, DateTime end, Filter filter, string interval = null, string function = null) { - RestRequest request = BuildRequest("/data/", Method.GET); - + RestRequest request = BuildRequest("/{version}/data/", Method.GET); + request.AddUrlSegment("version", _version); AddReadParameters(request, start, end, interval, function); if (filter != null) From 6388cfaa039798ed54cd7ee8392884557e09f312 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Fri, 25 Jan 2013 17:19:21 -0600 Subject: [PATCH 05/20] Add initial cursor implementation --- Client.Tests/CursorTests.cs | 18 ++++++++++++++++++ Client/Client.cs | 27 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 91ccc8b..57f28ef 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -62,5 +62,23 @@ public void Iterator() } Assert.AreEqual(expected, output); } + + [Test] + public void SmokeTest() + { + Client client = new Client("key", "secret", "localhost", 4242, "v1", false); + DateTime start = new DateTime(2012, 1, 1); + DateTime end = new DateTime(2012, 2, 1); + string interval = "raw"; + int count = 0; + + Cursor datapoints = client.ReadByKey2("myagley-1", start, end, interval); + foreach(DataPoint dp in datapoints) + { + count = count + 1; + Console.WriteLine(dp); + } + Console.WriteLine(count); + } } } diff --git a/Client/Client.cs b/Client/Client.cs index f9bfc95..1ba6390 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -378,6 +378,33 @@ private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTim return result; } + public virtual Cursor ReadById2(string seriesId, DateTime start, DateTime end, string interval=null, + string function=null) + { + return ReadCursor(SeriesProperty.Id, seriesId, start, end, interval, function); + } + + public virtual Cursor ReadByKey2(string seriesKey, DateTime start, DateTime end, string interval=null, + string function=null) + { + return ReadCursor(SeriesProperty.Key, seriesKey, start, end, interval, function); + } + + private Cursor ReadCursor(string seriesProperty, string propertyValue, DateTime start, DateTime end, + string interval=null, string function=null) + { + RestRequest request = BuildRequest("/{version}/series/{property}/{value}/data/segment/", Method.GET); + request.AddUrlSegment("version", _version); + request.AddUrlSegment("property", seriesProperty); + request.AddUrlSegment("value", propertyValue); + AddReadParameters(request, start, end, interval, function); + var response = Execute(request); + + Segment segment = new Segment(response); + SegmentEnumerator segments = new SegmentEnumerator(this, segment); + return new Cursor(segments); + } + /// /// Reads a list of DataSet by the provided filter and rolluped by the interval /// From 574152ac7b6d324df0677f0e562c43a6aa7b3870 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 16:53:37 -0600 Subject: [PATCH 06/20] Add more tests for the cursor --- Client.Tests/CursorTests.cs | 255 +++++++++++++++++++++++++++--------- Client.Tests/TestCommon.cs | 7 + Client/Client.cs | 2 +- 3 files changed, 204 insertions(+), 60 deletions(-) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 57f28ef..325dbb5 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -1,84 +1,221 @@ using Client; using Client.Model; +using Moq; using NUnit.Framework; +using RestSharp; using System; using System.Collections.Generic; +using System.Linq.Expressions; namespace Client.Tests { [TestFixture] - public class SegmentTests + public class CursorTests { - [Test] - public void Constructor() + [TestFixture] + class SegmentTests { - List data = new List { new DataPoint(new DateTime(2012, 3, 27), 12.34) }; - Segment segment = new Segment(data, "next"); - Assert.AreEqual(data, segment.Data); - Assert.AreEqual("next", segment.NextUrl); - } + [Test] + public void Constructor() + { + List data = new List { new DataPoint(new DateTime(2012, 3, 27), 12.34) }; + Segment segment = new Segment(data, "next"); + Assert.AreEqual(data, segment.Data); + Assert.AreEqual("next", segment.NextUrl); + } - [Test] - public void Deserialize() - { - string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}]"; - RestSharp.RestResponse response = new RestSharp.RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = content - }; - RestSharp.Parameter link = new RestSharp.Parameter { - Name = "Link", - Value = "; rel=\"next\"" - }; - response.Headers.Add(link); - - Segment segment = new Segment(response); - Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); - Assert.AreEqual(expected.Data, segment.Data); - Assert.AreEqual(expected.NextUrl, segment.NextUrl); + [Test] + public void Deserialize() + { + string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}]"; + RestSharp.RestResponse response = new RestSharp.RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + RestSharp.Parameter link = new RestSharp.Parameter { + Name = "Link", + Value = "; rel=\"next\"" + }; + response.Headers.Add(link); + + Segment segment = new Segment(response); + Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); + Assert.AreEqual(expected.Data, segment.Data); + Assert.AreEqual(expected.NextUrl, segment.NextUrl); + } + + [Test] + public void Iterator() + { + string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]"; + RestSharp.RestResponse response = new RestSharp.RestResponse + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + + Segment segment = new Segment(response); + List expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) + }; + + List output = new List(); + foreach(DataPoint dp in segment) + { + output.Add(dp); + } + Assert.AreEqual(expected, output); + } } - [Test] - public void Iterator() + [TestFixture] + class RequestTests { - string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]"; - RestSharp.RestResponse response = new RestSharp.RestResponse + [Test] + public void SingleSegmentSmokeTest() { - StatusCode = System.Net.HttpStatusCode.OK, - Content = content - }; - - Segment segment = new Segment(response); - List expected = new List { - new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), - new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) - }; - - List output = new List(); - foreach(DataPoint dp in segment) + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = new Mock(); + mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(response); + var client = TestCommon.GetClient(mockclient.Object); + var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + var expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) + }; + var output = new List(); + foreach(DataPoint dp in cursor) + { + output.Add(dp); + } + Assert.AreEqual(expected, output); + } + + [Test] + public void MultipleSegmentSmokeTest() { - output.Add(dp); + var response1 = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + response1.Headers.Add(new Parameter { + Name = "Link", + Value = "; rel=\"next\"" + }); + var response2 = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T02:00:00.000-05:00\",\"v\":34.56}]" + }; + var calls = 0; + RestResponse[] responses = { response1, response2 }; + var mockclient = new Mock(); + mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(() => responses[calls]).Callback(() => calls++); + + var client = TestCommon.GetClient(mockclient.Object); + var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + var expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45), + new DataPoint(new DateTime(2012, 3, 27, 2, 0, 0), 34.56) + }; + var output = new List(); + foreach(DataPoint dp in cursor) + { + output.Add(dp); + } + Assert.AreEqual(expected, output); } - Assert.AreEqual(expected, output); - } - [Test] - public void SmokeTest() - { - Client client = new Client("key", "secret", "localhost", 4242, "v1", false); - DateTime start = new DateTime(2012, 1, 1); - DateTime end = new DateTime(2012, 2, 1); - string interval = "raw"; - int count = 0; - - Cursor datapoints = client.ReadByKey2("myagley-1", start, end, interval); - foreach(DataPoint dp in datapoints) + [Test] + public void RequestMethod() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + Expression> assertion = req => req.Method == Method.GET; + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestStartTime() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadByKey2("testkey", start, end, IntervalParameter.Raw()); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-06-23T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestEndTime() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadByKey2("testkey", start, end, IntervalParameter.Raw()); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-06-24T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestUrl() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + + client.ReadByKey2("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data/segment/"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testkey")))); + } + + [Test] + public void RequestInterval() { - count = count + 1; - Console.WriteLine(dp); + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + + client.ReadByKey2("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "interval", "raw"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); } - Console.WriteLine(count); } } } diff --git a/Client.Tests/TestCommon.cs b/Client.Tests/TestCommon.cs index a7c98f5..ea0fce0 100644 --- a/Client.Tests/TestCommon.cs +++ b/Client.Tests/TestCommon.cs @@ -30,6 +30,13 @@ public static Client GetClient(RestClient restClient) return restClient; } + public static Mock GetMockRestClient(RestSharp.RestResponse res) + { + var restClient = new Mock(); + restClient.Setup(cl => cl.Execute(It.IsAny())).Returns(res); + return restClient; + } + public static Mock GetMockRestClient() { var res = new RestSharp.RestResponse diff --git a/Client/Client.cs b/Client/Client.cs index 1ba6390..06ea648 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -398,7 +398,7 @@ private Cursor ReadCursor(string seriesProperty, string propertyValue, DateTime request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); AddReadParameters(request, start, end, interval, function); - var response = Execute(request); + IRestResponse response = Execute(request); Segment segment = new Segment(response); SegmentEnumerator segments = new SegmentEnumerator(this, segment); From 82d3d1b2ab2b7952b531730fc0842f6975db66ce Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 17:15:10 -0600 Subject: [PATCH 07/20] Move the model tests into a Model directory --- .../{DataPointModelTests.cs => Model/DataPointTests.cs} | 2 +- Client.Tests/{SeriesModelTests.cs => Model/SeriesTests.cs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Client.Tests/{DataPointModelTests.cs => Model/DataPointTests.cs} (97%) rename Client.Tests/{SeriesModelTests.cs => Model/SeriesTests.cs} (98%) diff --git a/Client.Tests/DataPointModelTests.cs b/Client.Tests/Model/DataPointTests.cs similarity index 97% rename from Client.Tests/DataPointModelTests.cs rename to Client.Tests/Model/DataPointTests.cs index a320374..8082781 100644 --- a/Client.Tests/DataPointModelTests.cs +++ b/Client.Tests/Model/DataPointTests.cs @@ -9,7 +9,7 @@ namespace Client.Tests { [TestFixture] - class DataPointModelTests + class DataPointTests { [Test] public void Unequality_Timestamp() diff --git a/Client.Tests/SeriesModelTests.cs b/Client.Tests/Model/SeriesTests.cs similarity index 98% rename from Client.Tests/SeriesModelTests.cs rename to Client.Tests/Model/SeriesTests.cs index 1a0c65e..968c5dc 100644 --- a/Client.Tests/SeriesModelTests.cs +++ b/Client.Tests/Model/SeriesTests.cs @@ -9,7 +9,7 @@ namespace Client.Tests { [TestFixture] - class SeriesModelTests + class SeriesTests { [Test] public void Equality() From b3f1f8c5b61f8f1b4c01d2a0180097be690cca16 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 17:26:19 -0600 Subject: [PATCH 08/20] Move RestorePackages into a make command --- Client.Tests/Client.Tests.csproj | 8 ++++---- Client/TempoClient.csproj | 2 +- Makefile | 10 +++++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Client.Tests/Client.Tests.csproj b/Client.Tests/Client.Tests.csproj index 3598b10..de3d78e 100644 --- a/Client.Tests/Client.Tests.csproj +++ b/Client.Tests/Client.Tests.csproj @@ -13,7 +13,7 @@ v4.0 512 ..\ - true + false true @@ -53,14 +53,14 @@ - + + + - - diff --git a/Client/TempoClient.csproj b/Client/TempoClient.csproj index 3778663..83d9d54 100644 --- a/Client/TempoClient.csproj +++ b/Client/TempoClient.csproj @@ -13,7 +13,7 @@ v4.0 512 ..\ - true + false true diff --git a/Makefile b/Makefile index 7a351a0..3619a99 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: compile compile-test clean clean-build clean-test +.PHONY: compile compile-test update update-build update-test clean clean-build clean-test compile: xbuild Client/TempoClient.csproj @@ -6,6 +6,14 @@ compile: compile-test: compile xbuild Client.Tests/Client.Tests.csproj +update-build: + xbuild Client/TempoClient.csproj /t:RestorePackages + +update-test: + xbuild Client.Tests/TempoClient.csproj /t:RestorePackages + +update: update-build update-test + test: compile-test mono packages/NUnit.Runners.2.6.1/tools/nunit-console.exe Client.Tests/bin/Debug/Client.Tests.dll From ba571bebb9ea78f734c31ef3f7ec2c7b5ecbe2aa Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 17:39:00 -0600 Subject: [PATCH 09/20] Add a static method to Segment to create Segment from RestResponse This is in place of having an auxilliary constructor --- Client.Tests/CursorTests.cs | 4 ++-- Client/Client.cs | 2 +- Client/Cursor.cs | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 325dbb5..930c837 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -39,7 +39,7 @@ public void Deserialize() }; response.Headers.Add(link); - Segment segment = new Segment(response); + Segment segment = Segment.FromResponse(response); Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); Assert.AreEqual(expected.Data, segment.Data); Assert.AreEqual(expected.NextUrl, segment.NextUrl); @@ -55,7 +55,7 @@ public void Iterator() Content = content }; - Segment segment = new Segment(response); + Segment segment = Segment.FromResponse(response); List expected = new List { new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) diff --git a/Client/Client.cs b/Client/Client.cs index 06ea648..f31ffd0 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -400,7 +400,7 @@ private Cursor ReadCursor(string seriesProperty, string propertyValue, DateTime AddReadParameters(request, start, end, interval, function); IRestResponse response = Execute(request); - Segment segment = new Segment(response); + Segment segment = Segment.FromResponse(response); SegmentEnumerator segments = new SegmentEnumerator(this, segment); return new Cursor(segments); } diff --git a/Client/Cursor.cs b/Client/Cursor.cs index e4e382a..6d564f8 100644 --- a/Client/Cursor.cs +++ b/Client/Cursor.cs @@ -46,7 +46,7 @@ public IEnumerator GetEnumerator() { var request = client.BuildRequest(segment.NextUrl, Method.GET); var response = client.Execute(request); - segment = new Segment(response); + segment = Segment.FromResponse(response); yield return segment; } } @@ -65,12 +65,11 @@ public Segment(IList data, string next) /// For now, build the Segment by passing in a RestResponse. /// This should be handled by a deserializer in the future - public Segment(IRestResponse response) + public static Segment FromResponse(IRestResponse response) { /// Deserialize the data JsonDeserializer deserializer = new JsonDeserializer(); List data = deserializer.Deserialize>(response); - Data = data; /// Get the next link from the Link header Parameter header = null; @@ -100,7 +99,8 @@ public Segment(IRestResponse response) { next.TryGetValue("url", out nextUrl); } - NextUrl = nextUrl; + + return new Segment(data, nextUrl); } public IEnumerator GetEnumerator() @@ -111,7 +111,7 @@ public IEnumerator GetEnumerator() } } - private List> ParseHeaderLinks(string header) + private static List> ParseHeaderLinks(string header) { char[] replaceChars = {' ', '\'', '"'}; char[] replaceUrlChars = {'<', '>', ' ', '\'', '"'}; From 7e5a0c6ba53e12a19a891d66135eba080ffc8a4e Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 18:28:52 -0600 Subject: [PATCH 10/20] Fix the tests project filename in Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3619a99..4774afd 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ update-build: xbuild Client/TempoClient.csproj /t:RestorePackages update-test: - xbuild Client.Tests/TempoClient.csproj /t:RestorePackages + xbuild Client.Tests/Client.Tests.csproj /t:RestorePackages update: update-build update-test From 229257c8cdba93eea88059b3639837b5df165117 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 28 Jan 2013 19:19:59 -0600 Subject: [PATCH 11/20] Move json files into their own namespace --- Client.Tests/Client.Tests.csproj | 4 +- .../{ => Json}/JsonDeserializationTests.cs | 3 +- .../{ => Json}/JsonSerializationTests.cs | 3 +- Client/Client.cs | 11 ++-- Client/Cursor.cs | 2 +- Client/Json/DateTimeConverter.cs | 26 ++++++++ Client/Json/JsonDeserializer.cs | 20 +++++++ Client/Json/JsonSerializer.cs | 24 ++++++++ Client/JsonSerializer.cs | 59 ------------------- Client/TempoClient.csproj | 4 +- 10 files changed, 85 insertions(+), 71 deletions(-) rename Client.Tests/{ => Json}/JsonDeserializationTests.cs (99%) rename Client.Tests/{ => Json}/JsonSerializationTests.cs (99%) create mode 100644 Client/Json/DateTimeConverter.cs create mode 100644 Client/Json/JsonDeserializer.cs create mode 100644 Client/Json/JsonSerializer.cs delete mode 100644 Client/JsonSerializer.cs diff --git a/Client.Tests/Client.Tests.csproj b/Client.Tests/Client.Tests.csproj index de3d78e..5de930f 100644 --- a/Client.Tests/Client.Tests.csproj +++ b/Client.Tests/Client.Tests.csproj @@ -55,8 +55,8 @@ - - + + diff --git a/Client.Tests/JsonDeserializationTests.cs b/Client.Tests/Json/JsonDeserializationTests.cs similarity index 99% rename from Client.Tests/JsonDeserializationTests.cs rename to Client.Tests/Json/JsonDeserializationTests.cs index fcc0cba..03f14c8 100644 --- a/Client.Tests/JsonDeserializationTests.cs +++ b/Client.Tests/Json/JsonDeserializationTests.cs @@ -1,4 +1,5 @@ -using Client.Model; +using Client.Json; +using Client.Model; using Moq; using NUnit.Framework; using RestSharp; diff --git a/Client.Tests/JsonSerializationTests.cs b/Client.Tests/Json/JsonSerializationTests.cs similarity index 99% rename from Client.Tests/JsonSerializationTests.cs rename to Client.Tests/Json/JsonSerializationTests.cs index 0cb4745..8129fe8 100644 --- a/Client.Tests/JsonSerializationTests.cs +++ b/Client.Tests/Json/JsonSerializationTests.cs @@ -1,4 +1,5 @@ -using Client.Model; +using Client.Json; +using Client.Model; using Moq; using NUnit.Framework; using RestSharp; diff --git a/Client/Client.cs b/Client/Client.cs index f31ffd0..67d8854 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -1,7 +1,6 @@ +using Client.Json; using Client.Model; -using Newtonsoft.Json; using RestSharp; -using RestSharp.Deserializers; using System; using System.Collections.Generic; using System.Net; @@ -329,8 +328,8 @@ private void DeleteDataPoints(string seriesProperty, string propertyValue, DateT request.AddUrlSegment("version", _version); request.AddUrlSegment("property", seriesProperty); request.AddUrlSegment("value", propertyValue); - request.AddParameter(QueryStringParameter.Start, TempoDateTimeConvertor.ConvertDateTimeToString(start)); - request.AddParameter(QueryStringParameter.End, TempoDateTimeConvertor.ConvertDateTimeToString(end)); + request.AddParameter(QueryStringParameter.Start, DateTimeConvertor.ConvertDateTimeToString(start)); + request.AddParameter(QueryStringParameter.End, DateTimeConvertor.ConvertDateTimeToString(end)); Execute(request); } @@ -432,8 +431,8 @@ public virtual IList ReadMultipleSeries(DateTime start, DateTime end, F private static void AddReadParameters(IRestRequest request, DateTime start, DateTime end, string interval = null, string function = null) { - request.AddParameter(QueryStringParameter.Start, TempoDateTimeConvertor.ConvertDateTimeToString(start)); - request.AddParameter(QueryStringParameter.End, TempoDateTimeConvertor.ConvertDateTimeToString(end)); + request.AddParameter(QueryStringParameter.Start, DateTimeConvertor.ConvertDateTimeToString(start)); + request.AddParameter(QueryStringParameter.End, DateTimeConvertor.ConvertDateTimeToString(end)); if (!string.IsNullOrEmpty(interval)) { diff --git a/Client/Cursor.cs b/Client/Cursor.cs index 6d564f8..4d5d7e6 100644 --- a/Client/Cursor.cs +++ b/Client/Cursor.cs @@ -1,6 +1,6 @@ +using Client.Json; using Client.Model; using RestSharp; -using RestSharp.Deserializers; using System; using System.Collections.Generic; diff --git a/Client/Json/DateTimeConverter.cs b/Client/Json/DateTimeConverter.cs new file mode 100644 index 0000000..04bceff --- /dev/null +++ b/Client/Json/DateTimeConverter.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; + + +namespace Client.Json +{ + public class DateTimeConvertor : DateTimeConverterBase + { + + public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + { + writer.WriteValue(ConvertDateTimeToString(value)); + } + + public static string ConvertDateTimeToString(object value) + { + return ((DateTime)value).ToString("yyyy-MM-ddTHH:mm:ss.fffzzz"); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + { + return DateTime.Parse(reader.Value.ToString()); + } + } +} diff --git a/Client/Json/JsonDeserializer.cs b/Client/Json/JsonDeserializer.cs new file mode 100644 index 0000000..d01571e --- /dev/null +++ b/Client/Json/JsonDeserializer.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using RestSharp; +using RestSharp.Deserializers; + + +namespace Client.Json +{ + public class JsonDeserializer : IDeserializer + { + public T Deserialize(IRestResponse response) + { + return JsonConvert.DeserializeObject(response.Content); + } + + public string RootElement { get; set; } + public string Namespace { get; set; } + public string DateFormat { get; set; } + } +} diff --git a/Client/Json/JsonSerializer.cs b/Client/Json/JsonSerializer.cs new file mode 100644 index 0000000..ffd99b3 --- /dev/null +++ b/Client/Json/JsonSerializer.cs @@ -0,0 +1,24 @@ +using Newtonsoft.Json; +using RestSharp.Serializers; + + +namespace Client.Json +{ + public class JsonSerializer : ISerializer + { + public JsonSerializer() + { + ContentType = "application/json"; + } + + public string Serialize(object obj) + { + return JsonConvert.SerializeObject(obj, new DateTimeConvertor()); + } + + public string RootElement { get; set; } + public string Namespace { get; set; } + public string DateFormat { get; set; } + public string ContentType { get; set; } + } +} diff --git a/Client/JsonSerializer.cs b/Client/JsonSerializer.cs deleted file mode 100644 index 4b5820b..0000000 --- a/Client/JsonSerializer.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using RestSharp.Deserializers; -using RestSharp.Serializers; -using RestSharp; -using System; - - -namespace Client -{ - public class JsonDeserializer : IDeserializer - { - public T Deserialize(IRestResponse response) - { - return JsonConvert.DeserializeObject(response.Content); - } - - public string RootElement { get; set; } - public string Namespace { get; set; } - public string DateFormat { get; set; } - } - - public class JsonSerializer : ISerializer - { - public JsonSerializer() - { - ContentType = "application/json"; - } - - public string Serialize(object obj) - { - return JsonConvert.SerializeObject(obj, new TempoDateTimeConvertor()); - } - - public string RootElement { get; set; } - public string Namespace { get; set; } - public string DateFormat { get; set; } - public string ContentType { get; set; } - } - - public class TempoDateTimeConvertor : DateTimeConverterBase - { - - public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - writer.WriteValue(ConvertDateTimeToString(value)); - } - - public static string ConvertDateTimeToString(object value) - { - return ((DateTime)value).ToString("yyyy-MM-ddTHH:mm:ss.fffzzz"); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - return DateTime.Parse(reader.Value.ToString()); - } - } -} diff --git a/Client/TempoClient.csproj b/Client/TempoClient.csproj index 83d9d54..9edb2f5 100644 --- a/Client/TempoClient.csproj +++ b/Client/TempoClient.csproj @@ -50,7 +50,9 @@ - + + + From e032389bdd3b465e5a9fb3474700627b88622d2a Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Tue, 29 Jan 2013 14:54:44 -0600 Subject: [PATCH 12/20] Add rollup information for the response from the server --- Client.Tests/CursorTests.cs | 20 ++++++++++---------- Client/Cursor.cs | 9 ++++++++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 930c837..50042a2 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -28,7 +28,7 @@ public void Constructor() [Test] public void Deserialize() { - string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}]"; + string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}],\"rollup\":null}"; RestSharp.RestResponse response = new RestSharp.RestResponse { StatusCode = System.Net.HttpStatusCode.OK, Content = content @@ -48,7 +48,7 @@ public void Deserialize() [Test] public void Iterator() { - string content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]"; + string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}"; RestSharp.RestResponse response = new RestSharp.RestResponse { StatusCode = System.Net.HttpStatusCode.OK, @@ -78,7 +78,7 @@ public void SingleSegmentSmokeTest() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = new Mock(); mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(response); @@ -102,7 +102,7 @@ public void MultipleSegmentSmokeTest() { var response1 = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; response1.Headers.Add(new Parameter { Name = "Link", @@ -110,7 +110,7 @@ public void MultipleSegmentSmokeTest() }); var response2 = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T02:00:00.000-05:00\",\"v\":34.56}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T02:00:00.000-05:00\",\"v\":34.56}],\"rollup\":null}" }; var calls = 0; RestResponse[] responses = { response1, response2 }; @@ -138,7 +138,7 @@ public void RequestMethod() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); @@ -153,7 +153,7 @@ public void RequestStartTime() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); @@ -171,7 +171,7 @@ public void RequestEndTime() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); @@ -189,7 +189,7 @@ public void RequestUrl() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); @@ -206,7 +206,7 @@ public void RequestInterval() { var response = new RestResponse { StatusCode = System.Net.HttpStatusCode.OK, - Content = "[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}]" + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); diff --git a/Client/Cursor.cs b/Client/Cursor.cs index 4d5d7e6..8909c08 100644 --- a/Client/Cursor.cs +++ b/Client/Cursor.cs @@ -54,6 +54,12 @@ public IEnumerator GetEnumerator() public class Segment { + private class SegmentJson + { + public List Data { get; set; } + public Dictionary Rollup { get; set; } + } + public IList Data { get; set; } public string NextUrl { get; set; } @@ -69,7 +75,8 @@ public static Segment FromResponse(IRestResponse response) { /// Deserialize the data JsonDeserializer deserializer = new JsonDeserializer(); - List data = deserializer.Deserialize>(response); + var result = deserializer.Deserialize(response); + List data = result.Data; /// Get the next link from the Link header Parameter header = null; From c2d25faa4383049111ccec8cd6bf2a46b6314e24 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 11:59:09 -0600 Subject: [PATCH 13/20] Add a summary object --- Client.Tests/Json/JsonDeserializationTests.cs | 41 +++++++++++++++++++ Client/Model/Summary.cs | 14 +++++++ Client/TempoClient.csproj | 1 + 3 files changed, 56 insertions(+) create mode 100644 Client/Model/Summary.cs diff --git a/Client.Tests/Json/JsonDeserializationTests.cs b/Client.Tests/Json/JsonDeserializationTests.cs index 03f14c8..64c1418 100644 --- a/Client.Tests/Json/JsonDeserializationTests.cs +++ b/Client.Tests/Json/JsonDeserializationTests.cs @@ -173,5 +173,46 @@ public void EmptySummary() Assert.AreEqual(0, result.Summary.Count); } } + + [TestFixture] + class SummaryTests + { + static string jsonSummary = @"{ + ""mean"": 3.00, + ""sum"": 12.00, + ""min"": 2.00, + ""max"": 4.00, + ""stddev"": 0.8165, + ""ss"": 2.00, + ""count"": 4 + }"; + + [Test] + public void SmokeTest() + { + var jsonResponse = new RestResponse { + Content = SummaryTests.jsonSummary + }; + + var result = JsonDeserializationTests.deserializer.Deserialize(jsonResponse); + Assert.AreEqual(3.0, result["mean"]); + Assert.AreEqual(12.0, result["sum"]); + Assert.AreEqual(2.0, result["min"]); + Assert.AreEqual(4.0, result["max"]); + Assert.AreEqual(0.8165, result["stddev"]); + Assert.AreEqual(2.0, result["ss"]); + Assert.AreEqual(4, result["count"]); + } + + [Test] + public void Empty() + { + var jsonResponse = new RestResponse { + Content = "{}" + }; + var result = JsonDeserializationTests.deserializer.Deserialize(jsonResponse); + Assert.AreEqual(0, result.Count); + } + } } } diff --git a/Client/Model/Summary.cs b/Client/Model/Summary.cs new file mode 100644 index 0000000..9204a89 --- /dev/null +++ b/Client/Model/Summary.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + + +namespace Client.Model +{ + /// + /// Respresents summary statistics from a time range of a series. The Summary table contains + /// statistics for the time range (sum, mean, min, max, count, etc.) + /// + public class Summary : Dictionary + { + } +} diff --git a/Client/TempoClient.csproj b/Client/TempoClient.csproj index 9edb2f5..0c71752 100644 --- a/Client/TempoClient.csproj +++ b/Client/TempoClient.csproj @@ -62,6 +62,7 @@ + From 80e775b0f32ec259601fe89d2d435b69cb1e74d4 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 13:40:12 -0600 Subject: [PATCH 14/20] Rename cursor calls to ReadCursorById and ReadCursorByKey --- Client.Tests/CursorTests.cs | 14 +++++++------- Client/Client.cs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 50042a2..870c795 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -83,7 +83,7 @@ public void SingleSegmentSmokeTest() var mockclient = new Mock(); mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(response); var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); var expected = new List { new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), @@ -118,7 +118,7 @@ public void MultipleSegmentSmokeTest() mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(() => responses[calls]).Callback(() => calls++); var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); var expected = new List { new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), @@ -142,7 +142,7 @@ public void RequestMethod() }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadByKey2("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); Expression> assertion = req => req.Method == Method.GET; mockclient.Verify(cl => cl.Execute(It.Is(assertion))); @@ -160,7 +160,7 @@ public void RequestStartTime() var start = new DateTime(2012, 6, 23); var end = new DateTime(2012, 6, 24); - client.ReadByKey2("testkey", start, end, IntervalParameter.Raw()); + client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-06-23T00:00:00.000-05:00"); mockclient.Verify(cl => cl.Execute(It.Is(assertion))); @@ -178,7 +178,7 @@ public void RequestEndTime() var start = new DateTime(2012, 6, 23); var end = new DateTime(2012, 6, 24); - client.ReadByKey2("testkey", start, end, IntervalParameter.Raw()); + client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-06-24T00:00:00.000-05:00"); mockclient.Verify(cl => cl.Execute(It.Is(assertion))); @@ -194,7 +194,7 @@ public void RequestUrl() var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); - client.ReadByKey2("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data/segment/"))); mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); @@ -211,7 +211,7 @@ public void RequestInterval() var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); - client.ReadByKey2("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "interval", "raw"); mockclient.Verify(cl => cl.Execute(It.Is(assertion))); diff --git a/Client/Client.cs b/Client/Client.cs index 67d8854..b573dbc 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -377,13 +377,13 @@ private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTim return result; } - public virtual Cursor ReadById2(string seriesId, DateTime start, DateTime end, string interval=null, + public virtual Cursor ReadCursorById(string seriesId, DateTime start, DateTime end, string interval=null, string function=null) { return ReadCursor(SeriesProperty.Id, seriesId, start, end, interval, function); } - public virtual Cursor ReadByKey2(string seriesKey, DateTime start, DateTime end, string interval=null, + public virtual Cursor ReadCursorByKey(string seriesKey, DateTime start, DateTime end, string interval=null, string function=null) { return ReadCursor(SeriesProperty.Key, seriesKey, start, end, interval, function); From d18dc4c03442d88e8a642b6bf796be606cd5d707 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 13:50:07 -0600 Subject: [PATCH 15/20] Add docstrings for ReadCursorById and ReadCursorByKey --- Client/Client.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Client/Client.cs b/Client/Client.cs index b573dbc..c572621 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -377,12 +377,32 @@ private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTim return result; } + /// + /// Queries a range of time series data for a series referenced by id. Returns a cursor (enumerator) over this data + /// which allows forward, one-time iteration over the data. + /// + /// The id of the series + /// The start time of the range + /// The end time of the range + /// An interval for the rollup. (e.g. 1min, 15min, 1hour, 1day, 1month) + /// A function for the rollup. (e.g. min, max, sum, avg, stddev, count) + /// A Cursor public virtual Cursor ReadCursorById(string seriesId, DateTime start, DateTime end, string interval=null, string function=null) { return ReadCursor(SeriesProperty.Id, seriesId, start, end, interval, function); } + /// + /// Queries a range of time series data for a series referenced by key. Returns a cursor (enumerator) over this data + /// which allows forward, one-time iteration over the data. + /// + /// The id of the series + /// The start time of the range + /// The end time of the range + /// An interval for the rollup. (e.g. 1min, 15min, 1hour, 1day, 1month) + /// A function for the rollup. (e.g. min, max, sum, avg, stddev, count) + /// A Cursor public virtual Cursor ReadCursorByKey(string seriesKey, DateTime start, DateTime end, string interval=null, string function=null) { From 1403d0ca8d3dc7b07f2f8f68839511d173093329 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 14:37:19 -0600 Subject: [PATCH 16/20] Add summary methods to the client --- Client.Tests/Client.Tests.csproj | 1 + Client.Tests/CursorTests.cs | 2 +- Client.Tests/SummaryTests.cs | 88 ++++++++++++++++++++++++++++++++ Client/Client.cs | 20 ++++++++ 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 Client.Tests/SummaryTests.cs diff --git a/Client.Tests/Client.Tests.csproj b/Client.Tests/Client.Tests.csproj index 5de930f..25e96cd 100644 --- a/Client.Tests/Client.Tests.csproj +++ b/Client.Tests/Client.Tests.csproj @@ -62,6 +62,7 @@ + diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 870c795..5f78a49 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -142,7 +142,7 @@ public void RequestMethod() }; var mockclient = TestCommon.GetMockRestClient(response); var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); Expression> assertion = req => req.Method == Method.GET; mockclient.Verify(cl => cl.Execute(It.Is(assertion))); diff --git a/Client.Tests/SummaryTests.cs b/Client.Tests/SummaryTests.cs new file mode 100644 index 0000000..9d732fb --- /dev/null +++ b/Client.Tests/SummaryTests.cs @@ -0,0 +1,88 @@ +using Client; +using Client.Model; +using Moq; +using NUnit.Framework; +using RestSharp; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + + +namespace Client.Tests +{ + [TestFixture] + public class SummaryTests + { + + [Test] + public void SmokeTest() + { + var expected = new Summary { + {"mean", 3.0}, + {"sum", 12.0}, + {"min", 2.0}, + {"max", 4.0}, + {"stddev", 0.8165}, + {"ss", 2.0}, + {"count", 4} + }; + + var mockclient = TestCommon.GetMockRestClient(expected); + var client = TestCommon.GetClient(mockclient.Object); + var summary = client.ReadSummaryByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + Assert.AreEqual(expected, summary); + } + + [Test] + public void RequestMethod() + { + var mockclient = TestCommon.GetMockRestClient(new Summary()); + var client = TestCommon.GetClient(mockclient.Object); + client.ReadSummaryByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + Expression> assertion = req => req.Method == Method.GET; + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestStartTime() + { + var mockclient = TestCommon.GetMockRestClient(new Summary()); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadSummaryByKey("testkey", start, end); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-06-23T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestEndTime() + { + var mockclient = TestCommon.GetMockRestClient(new Summary()); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadSummaryByKey("testkey", start, end); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-06-24T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } + + [Test] + public void RequestUrl() + { + var mockclient = TestCommon.GetMockRestClient(new Summary()); + var client = TestCommon.GetClient(mockclient.Object); + + client.ReadSummaryByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24)); + + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data/summary/"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testkey")))); + } + } +} diff --git a/Client/Client.cs b/Client/Client.cs index c572621..aa529ed 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -424,6 +424,26 @@ private Cursor ReadCursor(string seriesProperty, string propertyValue, DateTime return new Cursor(segments); } + public virtual Summary ReadSummaryById(string seriesId, DateTime start, DateTime end) + { + return ReadSummary(SeriesProperty.Id, seriesId, start, end); + } + + public virtual Summary ReadSummaryByKey(string seriesKey, DateTime start, DateTime end) + { + return ReadSummary(SeriesProperty.Key, seriesKey, start, end); + } + + private Summary ReadSummary(string seriesProperty, string propertyValue, DateTime start, DateTime end) + { + RestRequest request = BuildRequest("/{version}/series/{property}/{value}/data/summary/", Method.GET); + request.AddUrlSegment("version", _version); + request.AddUrlSegment("property", seriesProperty); + request.AddUrlSegment("value", propertyValue); + AddReadParameters(request, start, end); + return Execute(request); + } + /// /// Reads a list of DataSet by the provided filter and rolluped by the interval /// From def45d8b64e2d94174adae42dd8f248f3cc13952 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 14:47:30 -0600 Subject: [PATCH 17/20] Break out the Segment and SegmentEnumerator into their own files --- Client.Tests/SummaryTests.cs | 1 - Client/Model/Cursor.cs | 26 ++++++++++++++ Client/{Cursor.cs => Model/Segment.cs} | 49 +------------------------- Client/Model/SegmentEnumerator.cs | 30 ++++++++++++++++ Client/TempoClient.csproj | 4 ++- 5 files changed, 60 insertions(+), 50 deletions(-) create mode 100644 Client/Model/Cursor.cs rename Client/{Cursor.cs => Model/Segment.cs} (74%) create mode 100644 Client/Model/SegmentEnumerator.cs diff --git a/Client.Tests/SummaryTests.cs b/Client.Tests/SummaryTests.cs index 9d732fb..c7482dd 100644 --- a/Client.Tests/SummaryTests.cs +++ b/Client.Tests/SummaryTests.cs @@ -13,7 +13,6 @@ namespace Client.Tests [TestFixture] public class SummaryTests { - [Test] public void SmokeTest() { diff --git a/Client/Model/Cursor.cs b/Client/Model/Cursor.cs new file mode 100644 index 0000000..f7cac3a --- /dev/null +++ b/Client/Model/Cursor.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + + +namespace Client.Model +{ + public class Cursor + { + private SegmentEnumerator segments; + + public Cursor(SegmentEnumerator segments) + { + this.segments = segments; + } + + public IEnumerator GetEnumerator() + { + foreach(Segment segment in segments) + { + foreach(DataPoint dp in segment) + { + yield return dp; + } + } + } + } +} diff --git a/Client/Cursor.cs b/Client/Model/Segment.cs similarity index 74% rename from Client/Cursor.cs rename to Client/Model/Segment.cs index 8909c08..f891253 100644 --- a/Client/Cursor.cs +++ b/Client/Model/Segment.cs @@ -1,57 +1,10 @@ using Client.Json; -using Client.Model; using RestSharp; -using System; using System.Collections.Generic; -namespace Client +namespace Client.Model { - public class Cursor - { - private SegmentEnumerator segments; - - public Cursor(SegmentEnumerator segments) - { - this.segments = segments; - } - - public IEnumerator GetEnumerator() - { - foreach(Segment segment in segments) - { - foreach(DataPoint dp in segment) - { - yield return dp; - } - } - } - } - - public class SegmentEnumerator - { - private Segment segment; - private Client client; - - public SegmentEnumerator(Client client, Segment segment) - { - this.client = client; - this.segment = segment; - } - - public IEnumerator GetEnumerator() - { - yield return segment; - while(segment.NextUrl != null) - { - var request = client.BuildRequest(segment.NextUrl, Method.GET); - var response = client.Execute(request); - segment = Segment.FromResponse(response); - yield return segment; - } - } - } - public class Segment { private class SegmentJson diff --git a/Client/Model/SegmentEnumerator.cs b/Client/Model/SegmentEnumerator.cs new file mode 100644 index 0000000..cab334c --- /dev/null +++ b/Client/Model/SegmentEnumerator.cs @@ -0,0 +1,30 @@ +using RestSharp; +using System.Collections.Generic; + + +namespace Client.Model +{ + public class SegmentEnumerator + { + private Segment segment; + private Client client; + + public SegmentEnumerator(Client client, Segment segment) + { + this.client = client; + this.segment = segment; + } + + public IEnumerator GetEnumerator() + { + yield return segment; + while(segment.NextUrl != null) + { + var request = client.BuildRequest(segment.NextUrl, Method.GET); + var response = client.Execute(request); + segment = Segment.FromResponse(response); + yield return segment; + } + } + } +} diff --git a/Client/TempoClient.csproj b/Client/TempoClient.csproj index 0c71752..4b56490 100644 --- a/Client/TempoClient.csproj +++ b/Client/TempoClient.csproj @@ -49,7 +49,6 @@ - @@ -58,9 +57,12 @@ + + + From 35ffe592004d36338e2f57eb38ac08fb6e7d0adb Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Wed, 30 Jan 2013 14:54:44 -0600 Subject: [PATCH 18/20] Move segmenttests into model directory --- Client.Tests/Client.Tests.csproj | 1 + Client.Tests/CursorTests.cs | 315 ++++++++++++----------------- Client.Tests/Model/SegmentTests.cs | 65 ++++++ 3 files changed, 193 insertions(+), 188 deletions(-) create mode 100644 Client.Tests/Model/SegmentTests.cs diff --git a/Client.Tests/Client.Tests.csproj b/Client.Tests/Client.Tests.csproj index 25e96cd..682fa29 100644 --- a/Client.Tests/Client.Tests.csproj +++ b/Client.Tests/Client.Tests.csproj @@ -58,6 +58,7 @@ + diff --git a/Client.Tests/CursorTests.cs b/Client.Tests/CursorTests.cs index 5f78a49..1314cbd 100644 --- a/Client.Tests/CursorTests.cs +++ b/Client.Tests/CursorTests.cs @@ -13,209 +13,148 @@ namespace Client.Tests [TestFixture] public class CursorTests { - [TestFixture] - class SegmentTests + [Test] + public void SingleSegmentSmokeTest() { - [Test] - public void Constructor() + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = new Mock(); + mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(response); + var client = TestCommon.GetClient(mockclient.Object); + var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + var expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) + }; + var output = new List(); + foreach(DataPoint dp in cursor) { - List data = new List { new DataPoint(new DateTime(2012, 3, 27), 12.34) }; - Segment segment = new Segment(data, "next"); - Assert.AreEqual(data, segment.Data); - Assert.AreEqual("next", segment.NextUrl); - } - - [Test] - public void Deserialize() - { - string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}],\"rollup\":null}"; - RestSharp.RestResponse response = new RestSharp.RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = content - }; - RestSharp.Parameter link = new RestSharp.Parameter { - Name = "Link", - Value = "; rel=\"next\"" - }; - response.Headers.Add(link); - - Segment segment = Segment.FromResponse(response); - Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); - Assert.AreEqual(expected.Data, segment.Data); - Assert.AreEqual(expected.NextUrl, segment.NextUrl); - } - - [Test] - public void Iterator() - { - string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}"; - RestSharp.RestResponse response = new RestSharp.RestResponse - { - StatusCode = System.Net.HttpStatusCode.OK, - Content = content - }; - - Segment segment = Segment.FromResponse(response); - List expected = new List { - new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), - new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) - }; - - List output = new List(); - foreach(DataPoint dp in segment) - { - output.Add(dp); - } - Assert.AreEqual(expected, output); + output.Add(dp); } + Assert.AreEqual(expected, output); } - [TestFixture] - class RequestTests + [Test] + public void MultipleSegmentSmokeTest() { - [Test] - public void SingleSegmentSmokeTest() + var response1 = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + response1.Headers.Add(new Parameter { + Name = "Link", + Value = "; rel=\"next\"" + }); + var response2 = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T02:00:00.000-05:00\",\"v\":34.56}],\"rollup\":null}" + }; + var calls = 0; + RestResponse[] responses = { response1, response2 }; + var mockclient = new Mock(); + mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(() => responses[calls]).Callback(() => calls++); + + var client = TestCommon.GetClient(mockclient.Object); + var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + var expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45), + new DataPoint(new DateTime(2012, 3, 27, 2, 0, 0), 34.56) + }; + var output = new List(); + foreach(DataPoint dp in cursor) { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = new Mock(); - mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(response); - var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); - - var expected = new List { - new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), - new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) - }; - var output = new List(); - foreach(DataPoint dp in cursor) - { - output.Add(dp); - } - Assert.AreEqual(expected, output); - } - - [Test] - public void MultipleSegmentSmokeTest() - { - var response1 = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - response1.Headers.Add(new Parameter { - Name = "Link", - Value = "; rel=\"next\"" - }); - var response2 = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T02:00:00.000-05:00\",\"v\":34.56}],\"rollup\":null}" - }; - var calls = 0; - RestResponse[] responses = { response1, response2 }; - var mockclient = new Mock(); - mockclient.Setup(cl => cl.Execute(It.IsAny())).Returns(() => responses[calls]).Callback(() => calls++); - - var client = TestCommon.GetClient(mockclient.Object); - var cursor = client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); - - var expected = new List { - new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), - new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45), - new DataPoint(new DateTime(2012, 3, 27, 2, 0, 0), 34.56) - }; - var output = new List(); - foreach(DataPoint dp in cursor) - { - output.Add(dp); - } - Assert.AreEqual(expected, output); + output.Add(dp); } + Assert.AreEqual(expected, output); + } - [Test] - public void RequestMethod() - { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = TestCommon.GetMockRestClient(response); - var client = TestCommon.GetClient(mockclient.Object); - client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); - - Expression> assertion = req => req.Method == Method.GET; - mockclient.Verify(cl => cl.Execute(It.Is(assertion))); - } + [Test] + public void RequestMethod() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + client.ReadCursorByKey("key1", new DateTime(2012, 3, 27), new DateTime(2012, 3, 28)); + + Expression> assertion = req => req.Method == Method.GET; + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } - [Test] - public void RequestStartTime() - { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = TestCommon.GetMockRestClient(response); - var client = TestCommon.GetClient(mockclient.Object); - var start = new DateTime(2012, 6, 23); - var end = new DateTime(2012, 6, 24); - - client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); - - Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-06-23T00:00:00.000-05:00"); - mockclient.Verify(cl => cl.Execute(It.Is(assertion))); - } + [Test] + public void RequestStartTime() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "start", "2012-06-23T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } - [Test] - public void RequestEndTime() - { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = TestCommon.GetMockRestClient(response); - var client = TestCommon.GetClient(mockclient.Object); - var start = new DateTime(2012, 6, 23); - var end = new DateTime(2012, 6, 24); - - client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); - - Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-06-24T00:00:00.000-05:00"); - mockclient.Verify(cl => cl.Execute(It.Is(assertion))); - } + [Test] + public void RequestEndTime() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + var start = new DateTime(2012, 6, 23); + var end = new DateTime(2012, 6, 24); + + client.ReadCursorByKey("testkey", start, end, IntervalParameter.Raw()); + + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "end", "2012-06-24T00:00:00.000-05:00"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); + } - [Test] - public void RequestUrl() - { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = TestCommon.GetMockRestClient(response); - var client = TestCommon.GetClient(mockclient.Object); - - client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); - - mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data/segment/"))); - mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); - mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testkey")))); - } + [Test] + public void RequestUrl() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); + + client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + + mockclient.Verify(cl => cl.Execute(It.Is(req => req.Resource == "/{version}/series/{property}/{value}/data/segment/"))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "property", "key")))); + mockclient.Verify(cl => cl.Execute(It.Is(req => TestCommon.ContainsParameter(req.Parameters, "value", "testkey")))); + } - [Test] - public void RequestInterval() - { - var response = new RestResponse { - StatusCode = System.Net.HttpStatusCode.OK, - Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" - }; - var mockclient = TestCommon.GetMockRestClient(response); - var client = TestCommon.GetClient(mockclient.Object); + [Test] + public void RequestInterval() + { + var response = new RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}" + }; + var mockclient = TestCommon.GetMockRestClient(response); + var client = TestCommon.GetClient(mockclient.Object); - client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); + client.ReadCursorByKey("testkey", new DateTime(2012, 06, 23), new DateTime(2012, 06, 24), IntervalParameter.Raw()); - Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "interval", "raw"); - mockclient.Verify(cl => cl.Execute(It.Is(assertion))); - } + Expression> assertion = req => TestCommon.ContainsParameter(req.Parameters, "interval", "raw"); + mockclient.Verify(cl => cl.Execute(It.Is(assertion))); } } } diff --git a/Client.Tests/Model/SegmentTests.cs b/Client.Tests/Model/SegmentTests.cs new file mode 100644 index 0000000..4ef22cf --- /dev/null +++ b/Client.Tests/Model/SegmentTests.cs @@ -0,0 +1,65 @@ +using Client.Model; +using NUnit.Framework; +using System; +using System.Collections.Generic; + + +namespace Client.Tests +{ + [TestFixture] + public class SegmentTests + { + [Test] + public void Constructor() + { + List data = new List { new DataPoint(new DateTime(2012, 3, 27), 12.34) }; + Segment segment = new Segment(data, "next"); + Assert.AreEqual(data, segment.Data); + Assert.AreEqual("next", segment.NextUrl); + } + + [Test] + public void Deserialize() + { + string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34}],\"rollup\":null}"; + RestSharp.RestResponse response = new RestSharp.RestResponse { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + RestSharp.Parameter link = new RestSharp.Parameter { + Name = "Link", + Value = "; rel=\"next\"" + }; + response.Headers.Add(link); + + Segment segment = Segment.FromResponse(response); + Segment expected = new Segment(new List{new DataPoint(new DateTime(2012, 3, 27), 12.34)}, "/v1/series/key/key1/data/segment/?start=2012-01-01&end=2012-01-02"); + Assert.AreEqual(expected.Data, segment.Data); + Assert.AreEqual(expected.NextUrl, segment.NextUrl); + } + + [Test] + public void Iterator() + { + string content = "{\"data\":[{\"t\":\"2012-03-27T00:00:00.000-05:00\",\"v\":12.34},{\"t\":\"2012-03-27T01:00:00.000-05:00\",\"v\":23.45}],\"rollup\":null}"; + RestSharp.RestResponse response = new RestSharp.RestResponse + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = content + }; + + Segment segment = Segment.FromResponse(response); + List expected = new List { + new DataPoint(new DateTime(2012, 3, 27, 0, 0, 0), 12.34), + new DataPoint(new DateTime(2012, 3, 27, 1, 0, 0), 23.45) + }; + + List output = new List(); + foreach(DataPoint dp in segment) + { + output.Add(dp); + } + Assert.AreEqual(expected, output); + } + } +} From c68d3dd3cdc57ea25302dacb595523d6c9dccb2d Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Thu, 31 Jan 2013 16:07:43 -0600 Subject: [PATCH 19/20] Add docstrings for the summary calls --- Client/Client.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Client/Client.cs b/Client/Client.cs index aa529ed..b91f9ca 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -379,7 +379,7 @@ private DataSet ReadDataSet(string seriesProperty, string propertyValue, DateTim /// /// Queries a range of time series data for a series referenced by id. Returns a cursor (enumerator) over this data - /// which allows forward, one-time iteration over the data. + /// which allows forward, one-time iteration. /// /// The id of the series /// The start time of the range @@ -395,7 +395,7 @@ public virtual Cursor ReadCursorById(string seriesId, DateTime start, DateTime e /// /// Queries a range of time series data for a series referenced by key. Returns a cursor (enumerator) over this data - /// which allows forward, one-time iteration over the data. + /// which allows forward, one-time iteration. /// /// The id of the series /// The start time of the range @@ -424,11 +424,23 @@ private Cursor ReadCursor(string seriesProperty, string propertyValue, DateTime return new Cursor(segments); } + /// + /// Reads a statistical summary for a range of data for a series referenced by id. + /// + /// The id of the series + /// The start time of the range + /// The end time of the range public virtual Summary ReadSummaryById(string seriesId, DateTime start, DateTime end) { return ReadSummary(SeriesProperty.Id, seriesId, start, end); } + /// + /// Reads a statistical summary for a range of data for a series referenced by key. + /// + /// The id of the series + /// The start time of the range + /// The end time of the range public virtual Summary ReadSummaryByKey(string seriesKey, DateTime start, DateTime end) { return ReadSummary(SeriesProperty.Key, seriesKey, start, end); From 27acc5577b3ad28b99beb4b2bb9bf2c475ac6818 Mon Sep 17 00:00:00 2001 From: Mike Yagley Date: Mon, 4 Feb 2013 14:45:09 -0600 Subject: [PATCH 20/20] Add documentation for the new methods --- README.md | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 38aa01b..73da68b 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ Stores the session information for authenticating and accessing TempoDB. Your ap also allows you to specify the hostname, port, and protocol (http or https). This is used if you are on a private cluster. #### Constructor -`` +``` Client(key, secret, host, port, version, secure, restClient) -`` +``` + * key - api key (string) * secret - api secret (string) * host - [Optional] hostname for cluster (string) @@ -27,7 +28,7 @@ Client(key, secret, host, port, version, secure, restClient) * secure - [Optional] protocol to use (true=https, false=http) * restClient - [Optional] rest client to use. Mainly used for testing. -```csharp +``` csharp var client = new Client("my-key", "my-secret"); ``` @@ -83,6 +84,14 @@ and a statistics summary table. The Summary table contains statistics for the ti * Data - datapoints ( List ) * Summary - a summary table of statistics for the queried range ( Dictionary ) +## Cursor +Represents an enumerable of DataPoints. This allows you to iterate over a very large number of datapoints for a single series without loading the entire result into memory. This class is a result of the ReadCursorBy* client functions. +### Members +* None, the object is enumerable + +## Summary +Represents a table of statistics for a rangle of data. This is dictionary of string->double. Values in the dictionary include mean, sum, minimum, maximum, standard deviation, and count. + ## Bulk Writes The Bulk classes exist to facilitate using the bulk write endpoint, which provides the ability to write to multiple series per timestamp. @@ -125,6 +134,10 @@ public void DeleteById(string seriesId, DateTime start, DateTime end) public void DeleteByKey(string seriesKey, DateTime start, DateTime end) public virtual DataSet ReadById(string seriesId, DateTime start, DateTime end, string interval = null, string function = null) public virtual DataSet ReadByKey(string seriesKey, DateTime start, DateTime end, string interval = null, string function = null) +public virtual Cursor ReadCursorById(string seriesId, DateTime start, DateTime end, string interval=null, string function=null) +public virtual Cursor ReadCursorByKey(string seriesKey, DateTime start, DateTime end, string interval=null, string function=null) +public virtual Summary ReadSummaryById(string seriesId, DateTime start, DateTime end) +public virtual Summary ReadSummaryByKey(string seriesKey, DateTime start, DateTime end) ``` ## CreateSeries(string key="") @@ -208,7 +221,6 @@ filter.AddAttribute("key", "val"); var series = client.ListSeries(filter); ``` - ## UpdateSeries(Series series) Updates a series. The series id is taken from the passed-in series object. Currently, only tags and attributes can be modified. The easiest way to use this method is through a read-modify-write cycle. @@ -221,6 +233,7 @@ The updated Series ### Example The following example reads the list of series with key *test1* and replaces the tags with *tag3*. + ```csharp var client = new Client("api-key", "api-secret"); @@ -282,7 +295,7 @@ var resultsRolledUp = client.ReadById("38268c3b231f1266a392931e15e99231", new Da var resultsRaw = client.ReadById("38268c3b231f1266a392931e15e99231", new DateTime(2012, 1, 1), new DateTime(2012, 1, 2)); ``` -## ReadByKey(string seriesId, DateTime start, DateTime end, string interval = null, string function = null) +## ReadByKey(string seriesKey, DateTime start, DateTime end, string interval = null, string function = null) Gets a DataSet by series key. The key, start, and end times are required. The same rollup rules apply as for the ReadByKey @@ -307,8 +320,98 @@ var client = new Client("api-key", "api-secret"); var data = client.ReadByKey("my-key", new DateTime(2012, 1, 1), new DateTime(2012, 2, 1), IntervalParameters.Days(1), FoldingFunction.Min); ``` -## WriteById(string seriesId, IList data) +##ReadCursorById(string seriesId, DateTime start, DateTime end, string interval = null, string function = null) +Gets a Cursor for the specified start/end times for a series referenced by id. The interval parameter allows you to specify a rollup period. For example, +"1hour" will roll the data up on the hour using the provided function. The function parameter specifies the folding function +to use while rolling the data up. The available folding functions and intervals are listed under the ReadById section above. + +### Parameters +* seriesId - the seriesId to include (string) +* start - start time for the query (DateTime) +* end - end time for the query (DateTime) +* interval - the rollup interval (string) +* function - the rollup folding function (string) + +### Returns +A Cursor over DataPoints. This is a one-time, forward enumerable over a range of datapoints. + +### Example + +The following example returns a Cursor from 2012-01-01 to 2012-01-02 for the series with id "38268c3b231f1266a392931e15e99231", +with the maximum value for each hour as well as the raw data. + +```csharp +var client = new Client("api-key", "api-secret"); + +var cursor = client.ReadCursorById("38268c3b231f1266a392931e15e99231", new DateTime(2012, 1, 1), new DateTime(2012, 1, 2), IntervalParameter.Hour(1), FoldingFunction.Max); +var cursorRaw = client.ReadCursorById("38268c3b231f1266a392931e15e99231", new DateTime(2012, 1, 1), new DateTime(2012, 1, 2)); +``` + +## ReadCursorByKey(string seriesKey, DateTime start, DateTime end, string interval = null, string function = null) + + +Gets a Cursor for the specified start/end times for a series referenced by key. The key, start, and end times are required. The interval parameter allows you to specify a rollup period. For example, +"1hour" will roll the data up on the hour using the provided function. The function parameter specifies the folding function +to use while rolling the data up. The available folding functions and intervals are listed under the ReadById section above. + +### Parameters +* seriesKey - key for the series to read from (string) +* start - start time for the query (DateTime) +* end - end time for the query (DateTime) +* interval - the rollup interval (string) +* function - the rollup folding function (string) + +### Returns +A Cursor over DataPoints. This is a one-time, forward enumerable over a range of datapoints. + +### Example + +The following example reads data for the series with id "my-key" from 2012-01-01 to 2012-02-01 and +returns a minimum datapoint per day. +```csharp +var client = new Client("api-key", "api-secret"); +var cursor = client.ReadCursorByKey("my-key", new DateTime(2012, 1, 1), new DateTime(2012, 2, 1), IntervalParameters.Days(1), FoldingFunction.Min); +``` + +## ReadSummaryById(string seriesId, DateTime start, DateTime end) +Gets a Summary for for a range of data for a series referenced by id. The key, start, and end times are required. + +### Parameters +* seriesId - id for the series to read from (string) +* start - start time for the query (DateTime) +* end - end time for the query (DateTime) + +### Returns +A Summary object. + +### Example + +The following example reads a summary object for the series with id "38268c3b231f1266a392931e15e99231" from 2012-01-01 to 2012-02-01. +```csharp +var client = new Client("api-key", "api-secret"); +var summary = client.ReadSummaryById("38268c3b231f1266a392931e15e99231", new DateTime(2012, 1, 1), new DateTime(2012, 2, 1)); +``` + +## ReadSummaryByKey(string seriesKey, DateTime start, DateTime end) +Gets a Summary for for a range of data for a series referenced by key. The key, start, and end times are required. + +### Parameters +* seriesKey - key for the series to read from (string) +* start - start time for the query (DateTime) +* end - end time for the query (DateTime) + +### Returns +A Summary object. + +### Example +The following example reads a summary object for the series with key "my-key" from 2012-01-01 to 2012-02-01. +```csharp +var client = new Client("api-key", "api-secret"); +var summary = client.ReadSummaryByKey("my-key", new DateTime(2012, 1, 1), new DateTime(2012, 2, 1)); +``` + +## WriteById(string seriesId, IList data) Writes datapoints to the specified series. The series id and a list of DataPoints are required. ### Parameters