/// <summary> /// ShouldCallBehavior handles all logic about whether a behavior should be invoked on a session. /// </summary> /// <param name="proxyBehavior">The relevant behavior</param> /// <param name="openSession">The relevant session</param> /// <param name="triggerFlag">The type of event</param> /// <returns>True if the behavior should be invoked on this session; false otherwise</returns> private bool ShouldCallBehavior(ProxyBehavior proxyBehavior, Session openSession, TriggerType triggerFlag) { return(TriggerType.None != (proxyBehavior.TriggerFlags & triggerFlag) && DateTime.Now < proxyBehavior.Options.Expiry && 0 < proxyBehavior.Options.RemainingSessions && proxyBehavior.Selector(openSession)); }
/// <summary> /// Initializes a new instance of the HttpMangler class with the given set of behaviors /// </summary> /// <param name="drainEventsOnShutdown">Determines if all sessions are allowed to complete on shutdown</param> /// <param name="behaviors">The behaviors to use while this class is alive</param> public HttpMangler(bool drainEventsOnShutdown, ProxyBehavior[] behaviors) { HttpMangler.Active = true; this.sessionCount = 0; this.behaviors = behaviors; this.drainSessions = drainEventsOnShutdown; FiddlerApplication.BeforeRequest += this.FiddlerApplication_BeforeRequest; FiddlerApplication.BeforeResponse += this.FiddlerApplication_BeforeResponse; FiddlerApplication.BeforeReturningError += this.FiddlerApplication_BeforeReturningError; FiddlerApplication.AfterSessionComplete += this.FiddlerApplication_AfterSessionComplete; FiddlerApplication.ResponseHeadersAvailable += this.FiddlerApplication_ResponseHeadersAvailable; }
/// <summary> /// ShouldCallBehavior handles all logic about whether a behavior should be invoked on a session. /// </summary> /// <param name="proxyBehavior">The relevant behavior</param> /// <param name="openSession">The relevant session</param> /// <param name="triggerFlag">The type of event</param> /// <returns>True if the behavior should be invoked on this session; false otherwise</returns> private bool ShouldCallBehavior(ProxyBehavior proxyBehavior, Session openSession, TriggerType triggerFlag) { return TriggerType.None != (proxyBehavior.TriggerFlags & triggerFlag) && DateTime.Now < proxyBehavior.Options.Expiry && 0 < proxyBehavior.Options.RemainingSessions && proxyBehavior.Selector(openSession); }
/// <summary> /// This help function is for getting the reference behavior of the Storage DLL when HttpMangler is enabled. /// Edit HttpMangler.cs to use HandleFiddlerEvent_DEBUG(). /// </summary> /// <param name="entityPartitionKey"></param> /// <param name="entityRowKey"></param> /// <param name="targetStorageAccount"></param> /// <param name="targetApiExpectedToFail"></param> /// <param name="behaviors"></param> protected void SetupAndRunXStoreHttpManglerTest( string entityPartitionKey, string entityRowKey, int targetStorageAccount, bool targetApiExpectedToFail, ProxyBehavior[] behaviors) { Assert.IsTrue(0 <= targetStorageAccount && targetStorageAccount < this.actualStorageAccountsUsed.Count, "targetStorageAccount={0} is out-of-range", targetStorageAccount); int index = this.actualStorageAccountsUsed[targetStorageAccount]; string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[index]; Console.WriteLine("accountNameToTamper={0}", accountNameToTamper); CloudTableClient tableClient = this.cloudTableClients[targetStorageAccount]; CloudTable table = tableClient.GetTableReference(this.repTable.TableName); // // Insert // string jobType = entityPartitionKey; string jobId = entityRowKey; string referenceMessage = SampleRTableEntity.GenerateRandomMessage(); SampleRTableEntity originalEntity = new SampleRTableEntity(jobType, jobId, referenceMessage); Console.WriteLine("\nCalling XStore Insert..."); TableOperation insertOperation = TableOperation.Insert(originalEntity); TableResult insertResult = table.Execute(insertOperation); Assert.IsNotNull(insertResult, "insertResult = null"); Console.WriteLine("insertResult.HttpStatusCode = {0}", insertResult.HttpStatusCode); Console.WriteLine("insertResult.ETag = {0}", insertResult.Etag); Assert.AreEqual((int)HttpStatusCode.NoContent, insertResult.HttpStatusCode, "insertResult.HttpStatusCode mismatch"); Assert.IsFalse(string.IsNullOrEmpty(insertResult.Etag), "insertResult.ETag = null or empty"); ITableEntity row = (ITableEntity)insertResult.Result; // // Retrieve // Console.WriteLine("Calling XStore Retrieve..."); TableOperation retrieveOperation = TableOperation.Retrieve<SampleRTableEntity>(row.PartitionKey, row.RowKey); TableResult retrieveResult = table.Execute(retrieveOperation); Assert.IsNotNull(retrieveResult, "retrieveResult = null"); Console.WriteLine("retrieveResult.HttpStatusCode = {0}", retrieveResult.HttpStatusCode); Assert.AreEqual((int)HttpStatusCode.OK, retrieveResult.HttpStatusCode, "retrieveResult.HttpStatusCode mismatch"); SampleRTableEntity retrievedEntity = (SampleRTableEntity)retrieveResult.Result; Console.WriteLine("retrieveEntity:\n{0}", retrievedEntity); Assert.IsTrue(originalEntity.Equals(retrievedEntity), "originalEntity != retrievedEntity"); // // Replace with HttpMangler enabled // Console.WriteLine("Calling XStore TableOperation.Replace with HttpMangler enabled..."); referenceMessage = SampleRTableEntity.GenerateRandomMessage(); retrievedEntity.Message = referenceMessage; TableOperation updateOperation = TableOperation.Replace(retrievedEntity); bool abortTest = false; try { using (HttpMangler proxy = new HttpMangler(false, behaviors)) { Console.WriteLine("Calling table.Execute(updateOperation)"); TableResult updateResult = table.Execute(updateOperation); if (targetApiExpectedToFail) { // if targetApi is expected to fail, and we are here, that means something is wrong. abortTest = true; throw new Exception("SetupAndRunXStoreHttpManglerTest(): Should not reach here. HttpMangler allowed an targetApi() to go through UNEXPECTEDLY."); } } } catch (Exception ex) { if (abortTest) { throw; } else { Console.WriteLine("\nException is Expected. targetApi(entity1) threw an exception: {0}\n", ex.ToString()); } } // // Retrieve again // Console.WriteLine("After HttpMangler is disabled, calling XStore Retrieve again..."); retrieveOperation = TableOperation.Retrieve<SampleRTableEntity>(row.PartitionKey, row.RowKey); retrieveResult = table.Execute(retrieveOperation); Assert.IsNotNull(retrieveResult, "retrieveResult = null"); Console.WriteLine("retrieveResult.HttpStatusCode = {0}", retrieveResult.HttpStatusCode); Assert.AreEqual((int)HttpStatusCode.OK, retrieveResult.HttpStatusCode, "retrieveResult.HttpStatusCode mismatch"); SampleRTableEntity retrievedEntity2 = (SampleRTableEntity)retrieveResult.Result; Console.WriteLine("retrieveEntity2:\n{0}", retrievedEntity2); Assert.IsTrue(originalEntity.Equals(retrievedEntity2), "originalEntity != retrievedEntity2"); }
/// <summary> /// Run the specified HttpMangler proxy behaviors for the specified batchOperation. /// </summary> /// <param name="batchOperation"></param> /// <param name="behaviors"></param> /// <param name="targetApiExpectedToFail"></param> /// <param name="httpManglerStartTime"></param> protected void RunHttpManglerBehaviorHelper( TableBatchOperation batchOperation, ProxyBehavior[] behaviors, bool targetApiExpectedToFail, out DateTime httpManglerStartTime) { // // Act // // Call targetApi(entity1) and tamper the request httpManglerStartTime = DateTime.UtcNow; Console.WriteLine("\nRunHttpManglerBehaviorHelper(): Call this.repTable.ExecuteBatch(batchOperation) with HttpMangler enabled..."); bool abortTest = false; try { using (HttpMangler proxy = new HttpMangler(false, behaviors)) { Console.WriteLine("Calling targetApi(entity1)"); this.repTable.ExecuteBatch(batchOperation); if (targetApiExpectedToFail) { // if targetApi is expected to fail, and we are here, that means something is wrong. abortTest = true; throw new Exception("RunHttpManglerBehaviorHelper(): Should not reach here. HttpMangler allowed this.repTable.ExecuteBatch(batchOperation) to go through UNEXPECTEDLY."); } } } catch (Exception ex) { if (targetApiExpectedToFail == false) { // if targetApi is NOT expected to fail, and we are here, that means something is wrong. throw new Exception( string.Format("RunHttpManglerBehaviorHelper(): this.repTable.ExecuteBatch(batchOperation) is NOT unexpected to throw an exception. Got this exception: {0}", ex.ToString())); } if (abortTest) { throw; } else { Console.WriteLine("\nException is Expected. this.repTable.ExecuteBatch(batchOperation) threw an exception: {0}\n", ex.ToString()); } } }
/// <summary> /// Run the specified HttpMangler proxy behaviors for the specified Api, which takes this form: /// Func<string, string, SampleRTableEntity> targetApi /// </summary> /// <param name="originalEntity"></param> /// <param name="behaviors"></param> /// <param name="targetApi"></param> /// <param name="targetApiExpectedToFail"></param> /// <param name="httpManglerStartTime"></param> protected void RunHttpManglerBehaviorHelper( SampleRTableEntity originalEntity, ProxyBehavior[] behaviors, Func<string, string, SampleRTableEntity> targetApi, bool targetApiExpectedToFail, out DateTime httpManglerStartTime) { // // Act // // Call targetApi(entity1) and tamper the request httpManglerStartTime = DateTime.UtcNow; Console.WriteLine("\nRunHttpManglerBehaviorHelper(): Call targetApi(entity1) with HttpMangler enabled..."); originalEntity.Message = SampleRTableEntity.GenerateRandomMessage(); bool abortTest = false; try { using (HttpMangler proxy = new HttpMangler(false, behaviors)) { Console.WriteLine("Calling targetApi(entity1)"); targetApi(originalEntity.PartitionKey, originalEntity.RowKey); if (targetApiExpectedToFail) { // if targetApi is expected to fail, and we are here, that means something is wrong. abortTest = true; throw new Exception("RunHttpManglerBehaviorHelper(): Should not reach here. HttpMangler allowed an targetApi() to go through UNEXPECTEDLY."); } } } catch (Exception ex) { if (targetApiExpectedToFail == false) { // if targetApi is NOT expected to fail, and we are here, that means something is wrong. throw new Exception( string.Format("RunHttpManglerBehaviorHelper(): targetApi() is NOT unexpected to throw an exception. Got this exception: {0}", ex.ToString())); } if (abortTest) { throw; } else { Console.WriteLine("\nException is Expected. targetApi(entity1) threw an exception: {0}\n", ex.ToString()); } } }
/// <summary> /// Helper function to set up an original entity and then run the specified HttpMangler Behavior. /// It will return the original entity created. /// Step (1): Make sure "entity1" with the specified partitionKey and rowKey exists. If not create it. Read "entity1". /// Step (2): Read "entity1" from individual storage tables directly for debugging. /// Step (3): Turn on HttpMangler and the specified behavior and call the specified RTable API to operate on "entity1". /// This function accepts a targetApi with this form: Func<string, string, SampleRTableEntity> targetApi /// </summary> /// <param name="entityPartitionKey"></param> /// <param name="entityRowKey"></param> /// <param name="behaviors"></param> /// <param name="targetApi"></param> /// <param name="targetApiExpectedToFail"></param> /// <returns></returns> private SampleRTableEntity SetupAndRunHttpManglerBehaviorHelper( string entityPartitionKey, string entityRowKey, ProxyBehavior[] behaviors, Func<string, string, SampleRTableEntity> targetApi, bool targetApiExpectedToFail) { DateTime httpManglerStartTime; SampleRTableEntity originalEntity = new SampleRTableEntity(); // "entity1": string jobType = entityPartitionKey; string jobId = entityRowKey; string referenceMessage = SampleRTableEntity.GenerateRandomMessage(); // // Arrange // // Make sure an entity exists with the specified partitionKey and rowKey Console.WriteLine("\nMaking sure entity1 exists..."); SampleRTableEntity entity1 = this.rtableWrapper.ReadEntity(jobType, jobId); if (entity1 == null) { SampleRTableEntity createEntity1 = new SampleRTableEntity(jobType, jobId, referenceMessage); this.rtableWrapper.InsertRow(createEntity1); entity1 = this.rtableWrapper.ReadEntity(jobType, jobId); } else { // entity1 already exists. Save the value of its Message for later use referenceMessage = entity1.Message; } Assert.IsNotNull(entity1, "entity1 is null UNEXPECTEDLY."); Console.WriteLine("entity1:\n{0}", entity1.ToString()); Assert.IsTrue(entity1.JobType == jobType, "entity.JobType is incorrect."); Assert.IsTrue(entity1.JobId == jobId, "entity.JobId is incorrect."); originalEntity = entity1.Clone(); // Read from Storage Accounts directly for debugging. Check for consistency of different accounts. this.ReadFromIndividualAccountsDirectly(jobType, jobId, true); this.RunHttpManglerBehaviorHelper( entity1, behaviors, targetApi, targetApiExpectedToFail, out httpManglerStartTime); return originalEntity; }