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