PageRenderTime 36ms CodeModel.GetById 3ms app.highlight 27ms RepoModel.GetById 2ms app.codeStats 0ms

/src/EventStore.Core.Tests/Http/HttpBehaviorSpecification.cs

https://github.com/elainte/EventStore
C# | 477 lines | 432 code | 44 blank | 1 comment | 36 complexity | f5026627e6a8556a8d1c7f7fc33287a1 MD5 | raw file
  1using System;
  2using System.Diagnostics;
  3using System.IO;
  4using System.Linq;
  5using System.Linq.Expressions;
  6using System.Net;
  7using System.Reflection;
  8using System.Text;
  9using System.Xml;
 10using System.Xml.Linq;
 11using EventStore.ClientAPI;
 12using EventStore.Common.Utils;
 13using EventStore.Core.Tests.ClientAPI.Helpers;
 14using EventStore.Core.Tests.Helpers;
 15using EventStore.Core.Tests.Http.Streams;
 16using EventStore.Core.Tests.Http.Users;
 17using NUnit.Framework;
 18using Newtonsoft.Json;
 19using Newtonsoft.Json.Linq;
 20
 21namespace EventStore.Core.Tests.Http
 22{
 23    public abstract class HttpBehaviorSpecification : SpecificationWithDirectoryPerTestFixture
 24    {
 25        protected MiniNode _node;
 26        protected IEventStoreConnection _connection;
 27        protected HttpWebResponse _lastResponse;
 28        protected string _lastResponseBody;
 29        protected JsonException _lastJsonException;
 30#if !__MonoCS__
 31        private Func<HttpWebResponse, byte[]> _dumpResponse;
 32        private Func<HttpWebResponse, int> _dumpResponse2;
 33        private Func<HttpWebRequest, byte[]> _dumpRequest;
 34        private Func<HttpWebRequest, byte[]> _dumpRequest2;
 35#endif
 36        private string _tag;
 37
 38        [TestFixtureSetUp]
 39        public override void TestFixtureSetUp()
 40        {
 41#if !__MonoCS__
 42            Helper.EatException(() => _dumpResponse = CreateDumpResponse());
 43            Helper.EatException(() => _dumpResponse2 = CreateDumpResponse2());
 44            Helper.EatException(() => _dumpRequest = CreateDumpRequest());
 45            Helper.EatException(() => _dumpRequest2 = CreateDumpRequest2());
 46#endif
 47
 48            base.TestFixtureSetUp();
 49
 50            bool createdMiniNode = false;
 51            if (SetUpFixture._connection != null && SetUpFixture._node != null)
 52            {
 53                _tag = "_" + (++SetUpFixture._counter);
 54                _node = SetUpFixture._node;
 55                _connection = SetUpFixture._connection;
 56            }
 57            else
 58            {
 59                createdMiniNode = true;
 60                _tag = "_1";
 61                _node = CreateMiniNode();
 62                _node.Start();
 63
 64                _connection = TestConnection.Create(_node.TcpEndPoint);
 65                _connection.ConnectAsync().Wait();
 66            }
 67            _lastResponse = null;
 68            _lastResponseBody = null;
 69            _lastJsonException = null;
 70            try
 71            {
 72                Given();
 73                When();
 74            }
 75            catch
 76            {
 77                if (createdMiniNode)
 78                {
 79                    if (_connection != null)
 80                        try
 81                        {
 82                            _connection.Close();
 83                        }
 84                        catch
 85                        {
 86                        }
 87                    if (_node != null)
 88                        try
 89                        {
 90                            _node.Shutdown();
 91                        }
 92                        catch
 93                        {
 94                        }
 95                }
 96                throw;
 97            }
 98        }
 99
100        public string TestStream {
101            get { return "/streams/test" + Tag; }
102        }
103
104        public string TestStreamName {
105            get { return "test" + Tag; }
106        }
107
108        public string TestMetadataStream {
109            get { return "/streams/$$test" + Tag; }
110        }
111
112        public string Tag
113        {
114            get { return _tag; }
115        }
116
117        protected virtual MiniNode CreateMiniNode()
118        {
119            return new MiniNode(PathName, skipInitializeStandardUsersCheck: GivenSkipInitializeStandardUsersCheck());
120        }
121
122        protected virtual bool GivenSkipInitializeStandardUsersCheck()
123        {
124            return false;
125        }
126
127        [TestFixtureTearDown]
128        public override void TestFixtureTearDown()
129        {
130            if (SetUpFixture._connection == null || SetUpFixture._node == null)
131            {
132                _connection.Close();
133                _node.Shutdown();
134            }
135            base.TestFixtureTearDown();
136        }
137
138        protected HttpWebRequest CreateRequest(
139            string path, string extra, string method, string contentType, ICredentials credentials = null)
140        {
141			var uri = MakeUrl (path, extra);
142			var request = WebRequest.Create (uri);
143            var httpWebRequest = (HttpWebRequest)request;
144            httpWebRequest.ConnectionGroupName = TestStream;
145            httpWebRequest.Method = method;
146            httpWebRequest.ContentType = contentType;
147            httpWebRequest.UseDefaultCredentials = false;
148            if (credentials != null)
149            {
150                httpWebRequest.Credentials = credentials;
151				httpWebRequest.PreAuthenticate = true;
152            }
153            return httpWebRequest;
154        }
155
156        protected HttpWebRequest CreateRequest(string path, string method, ICredentials credentials = null)
157        {
158            var httpWebRequest = (HttpWebRequest) WebRequest.Create(MakeUrl(path));
159            httpWebRequest.Method = method;
160            httpWebRequest.UseDefaultCredentials = false;
161            if (credentials != null)
162            {
163                httpWebRequest.Credentials = credentials;
164				httpWebRequest.PreAuthenticate = true;
165            }
166            return httpWebRequest;
167        }
168        
169        protected Uri MakeUrl(string path, string extra = "")
170        {
171			//Note: this hack fixes Mono URI encoding the `?`
172			var components = path.Split('?');
173			Console.WriteLine("Path: " + path);
174			Console.WriteLine("Components Length: " + components.Length);
175
176			var supplied = new Uri(components[0], UriKind.RelativeOrAbsolute);
177			if (components.Length > 1)
178			{
179				var builder = new UriBuilder(supplied);
180				builder.Query = components[1];
181				supplied = builder.Uri;
182			}
183
184            if (supplied.IsAbsoluteUri && !supplied.IsFile) // NOTE: is file important for mono
185                return supplied;
186
187            var httpEndPoint = _node.HttpEndPoint;
188			var finalBuilder = new UriBuilder("http", httpEndPoint.Address.ToString(), httpEndPoint.Port, components[0], extra);
189
190			if (components.Length > 1)
191				finalBuilder.Query = components[1];
192
193			return finalBuilder.Uri;
194        }
195
196        protected HttpWebResponse MakeJsonPost<T>(string path, T body, ICredentials credentials = null)
197        {
198            var request = CreateRawJsonPostRequest(path, "POST", body, credentials);
199            var httpWebResponse = GetRequestResponse(request);
200            return httpWebResponse;
201        }
202
203        protected HttpWebResponse MakeArrayEventsPost<T>(string path, T body, ICredentials credentials=null) {
204            var request = CreateEventsJsonPostRequest(path, "POST", body, credentials);
205            var response = GetRequestResponse(request);
206            return response;
207        }
208
209        protected HttpWebResponse MakeRawJsonPost<T>(string path, T body, ICredentials credentials = null)
210        {
211            var request = CreateRawJsonPostRequest(path, "POST", body, credentials);
212            var httpWebResponse = GetRequestResponse(request);
213            return httpWebResponse;
214        }
215
216        protected JObject MakeJsonPostWithJsonResponse<T>(string path, T body, ICredentials credentials = null)
217        {
218            var request = CreateRawJsonPostRequest(path, "POST", body, credentials);
219            _lastResponse = GetRequestResponse(request);
220            var memoryStream = new MemoryStream();
221            _lastResponse.GetResponseStream().CopyTo(memoryStream);
222            var bytes = memoryStream.ToArray();
223            _lastResponseBody = Helper.UTF8NoBom.GetString(bytes);
224            try
225            {
226                return _lastResponseBody.ParseJson<JObject>();
227            }
228            catch (JsonException ex)
229            {
230                _lastJsonException = ex;
231                return default(JObject);
232            }
233        }
234
235        protected JObject MakeJsonEventsPostWithJsonResponse<T>(string path, T body, ICredentials credentials = null)
236        {
237            var request = CreateEventsJsonPostRequest(path, "POST", body, credentials);
238            _lastResponse = GetRequestResponse(request);
239            var memoryStream = new MemoryStream();
240            _lastResponse.GetResponseStream().CopyTo(memoryStream);
241            var bytes = memoryStream.ToArray();
242            _lastResponseBody = Helper.UTF8NoBom.GetString(bytes);
243            try
244            {
245                return _lastResponseBody.ParseJson<JObject>();
246            }
247            catch (JsonException ex)
248            {
249                _lastJsonException = ex;
250                return default(JObject);
251            }
252        }
253
254
255        protected HttpWebResponse MakeEventsJsonPut<T>(string path, T body, ICredentials credentials)
256        {
257            var request = CreateEventsJsonPostRequest(path, "PUT", body, credentials);
258            var httpWebResponse = GetRequestResponse(request);
259            return httpWebResponse;
260        }
261
262        protected HttpWebResponse MakeRawJsonPut<T>(string path, T body, ICredentials credentials)
263        {
264            var request = CreateRawJsonPostRequest(path, "PUT", body, credentials);
265            var httpWebResponse = GetRequestResponse(request);
266            return httpWebResponse;
267        }
268
269        protected HttpWebResponse MakeDelete(string path, ICredentials credentials = null)
270        {
271            var request = CreateRequest(path, "DELETE", credentials);
272            var httpWebResponse = GetRequestResponse(request);
273            return httpWebResponse;
274        }
275
276        protected HttpWebResponse MakePost(string path, ICredentials credentials = null)
277        {
278            var request = CreateJsonPostRequest(path, credentials);
279            var httpWebResponse = GetRequestResponse(request);
280            return httpWebResponse;
281        }
282        
283        protected XDocument GetXml(string path, ICredentials credentials = null)
284        {
285            Get(path, "", "application/atom+xml", credentials);
286            return XDocument.Parse(_lastResponseBody);
287        }
288
289        protected T GetJson<T>(string path, string accept = null, ICredentials credentials = null)
290        {
291            Get(path, "", accept, credentials);
292            try
293            {
294                return _lastResponseBody.ParseJson<T>();
295            }
296            catch (JsonException ex)
297            {
298                _lastJsonException = ex;
299                return default(T);
300            }
301        }
302
303        protected T GetJson2<T>(string path, string extra, string accept = null, ICredentials credentials = null)
304        {
305            Get(path, extra, accept, credentials);
306            try
307            {
308                return _lastResponseBody.ParseJson<T>();
309            }
310            catch (JsonException ex)
311            {
312                _lastJsonException = ex;
313                return default(T);
314            }
315        }
316
317        protected void Get(string path, string extra, string accept = null, ICredentials credentials = null)
318        {
319            var request = CreateRequest(path, extra, "GET", null, credentials);
320            request.Accept = accept ?? "application/json";
321            _lastResponse = GetRequestResponse(request);
322            var memoryStream = new MemoryStream();
323            _lastResponse.GetResponseStream().CopyTo(memoryStream);
324            var bytes = memoryStream.ToArray();
325            _lastResponseBody = Helper.UTF8NoBom.GetString(bytes);
326        }
327
328        protected HttpWebResponse GetRequestResponse(HttpWebRequest request)
329        {
330            HttpWebResponse response;
331            try
332            {
333                response = (HttpWebResponse) request.GetResponse();
334            }
335            catch (WebException ex)
336            {
337                response = (HttpWebResponse) ex.Response;
338            }
339#if !__MonoCS__
340            if (_dumpRequest != null)
341            {
342                var bytes = _dumpRequest(request);
343                if (bytes != null)
344                    Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, GetBytesLength(bytes)).TrimEnd('\0'));
345            }
346            if (_dumpRequest2 != null)
347            {
348                var bytes = _dumpRequest2(request);
349                if (bytes != null)
350                    Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, GetBytesLength(bytes)).TrimEnd('\0'));
351            }
352            Console.WriteLine();
353            if (_dumpResponse != null)
354            {
355                var bytes = _dumpResponse(response);
356                var len = _dumpResponse2(response);
357                if (bytes != null)
358                    Console.WriteLine(Encoding.ASCII.GetString(bytes, 0, len).TrimEnd('\0'));
359            }
360#endif
361            return response;
362        }
363
364        private int GetBytesLength(byte[] bytes)
365        {
366            var index = Array.IndexOf(bytes, 0);
367            return index < 0 ? bytes.Length : index;
368        }
369
370        protected HttpWebRequest CreateEventsJsonPostRequest<T>(
371            string path, string method, T body, ICredentials credentials = null)
372        {
373            var request = CreateRequest(path, "", method, "application/vnd.eventstore.events+json", credentials);
374            request.GetRequestStream().WriteJson(body);
375            return request;
376        }
377
378        protected HttpWebRequest CreateRawJsonPostRequest<T>(
379            string path, string method, T body, ICredentials credentials = null)
380        {
381            var request = CreateRequest(path, "", method, "application/json", credentials);
382            request.GetRequestStream().WriteJson(body);
383            return request;
384        }
385
386        private HttpWebRequest CreateJsonPostRequest(string path, ICredentials credentials = null)
387        {
388            var request = CreateRequest(path, "POST", credentials);
389            request.ContentLength = 0;
390            return request;
391        }
392
393        protected abstract void Given();
394        protected abstract void When();
395
396        private static Func<HttpWebResponse, byte[]> CreateDumpResponse()
397        {
398            var r = Expression.Parameter(typeof (HttpWebResponse), "r");
399            var piCoreResponseData = typeof (HttpWebResponse).GetProperty(
400                "CoreResponseData",
401                BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
402            var fim_ConnectStream = piCoreResponseData.PropertyType.GetField("m_ConnectStream",
403                                                                             BindingFlags.GetField| BindingFlags.Public | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
404            var connectStreamType = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType("System.Net.ConnectStream")).Where(t => t != null).FirstOrDefault();
405            var fim_ReadBuffer = connectStreamType.GetField("m_ReadBuffer",
406                                                            BindingFlags.GetField| BindingFlags.NonPublic | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
407            var body = Expression.Field(Expression.Convert(Expression.Field(Expression.Property(r, piCoreResponseData), fim_ConnectStream), connectStreamType), fim_ReadBuffer);
408            var debugExpression = Expression.Lambda<Func<HttpWebResponse, byte[]>>(body, r);
409            return debugExpression.Compile();
410        }
411
412        private static Func<HttpWebResponse, int> CreateDumpResponse2()
413        {
414            var r = Expression.Parameter(typeof (HttpWebResponse), "r");
415            var piCoreResponseData = typeof (HttpWebResponse).GetProperty(
416                "CoreResponseData",
417                BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
418            var fim_ConnectStream = piCoreResponseData.PropertyType.GetField("m_ConnectStream",
419                                                                             BindingFlags.GetField| BindingFlags.Public | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
420            var connectStreamType = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType("System.Net.ConnectStream")).Where(t => t != null).FirstOrDefault();
421            var fim_ReadOffset = connectStreamType.GetField("m_ReadOffset",
422                                                            BindingFlags.GetField| BindingFlags.NonPublic | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
423            var fim_ReadBufferSize = connectStreamType.GetField("m_ReadBufferSize",
424                                                            BindingFlags.GetField| BindingFlags.NonPublic | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
425            var stream = Expression.Convert(Expression.Field(Expression.Property(r, piCoreResponseData), fim_ConnectStream), connectStreamType);
426            var body = Expression.Add(Expression.Field(stream, fim_ReadOffset), Expression.Field(stream, fim_ReadBufferSize));
427            var debugExpression = Expression.Lambda<Func<HttpWebResponse, int>>(body, r);
428            return debugExpression.Compile();
429        }
430
431        private static Func<HttpWebRequest, byte[]> CreateDumpRequest()
432        {
433            var r = Expression.Parameter(typeof (HttpWebRequest), "r");
434            var fi_WriteBuffer = typeof (HttpWebRequest).GetField("_WriteBuffer",
435                                                                  BindingFlags.GetField| BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy| BindingFlags.Instance);
436            var body = Expression.Field(r, fi_WriteBuffer);
437            var debugExpression = Expression.Lambda<Func<HttpWebRequest, byte[]>>(body, r);
438            return debugExpression.Compile();
439        }
440
441        private static Func<HttpWebRequest, byte[]> CreateDumpRequest2()
442        {
443            var r = Expression.Parameter(typeof (HttpWebRequest), "r");
444            var fi_SubmitWriteStream = typeof (HttpWebRequest).GetField(
445                "_SubmitWriteStream",
446                BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy
447                | BindingFlags.Instance);
448            var connectStreamType = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType("System.Net.ConnectStream")).Where(t => t != null).FirstOrDefault();
449            var piBufferedData = connectStreamType.GetProperty(
450                "BufferedData",
451                BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy
452                | BindingFlags.Instance);
453            var fiheadChunk = piBufferedData.PropertyType.GetField(
454                "headChunk",
455                BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy
456                | BindingFlags.Instance);
457            var piBuffer = fiheadChunk.FieldType.GetField(
458                "Buffer",
459                BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy
460                | BindingFlags.Instance);
461            var submitWriteStreamExpression = Expression.Field(r, fi_SubmitWriteStream);
462            var headChunk =
463                Expression.Condition(Expression.ReferenceNotEqual(submitWriteStreamExpression, Expression.Constant(null, submitWriteStreamExpression.Type)),
464                Expression.Field(
465                    Expression.Property(
466                        Expression.Convert(submitWriteStreamExpression, connectStreamType), piBufferedData),
467                    fiheadChunk),
468                    Expression.Constant(null, fiheadChunk.FieldType));
469            var body =
470                Expression.Condition(
471                    Expression.ReferenceNotEqual(headChunk, Expression.Constant(null, headChunk.Type)),
472                    Expression.Field(headChunk, piBuffer), Expression.Constant(null, piBuffer.FieldType));
473            var debugExpression = Expression.Lambda<Func<HttpWebRequest, byte[]>>(body, r);
474            return debugExpression.Compile();
475        }
476    }
477}