public void B00ThrottleDeleteRowInnerTest() { this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable); string entityPartitionKey = "jobType-ThrottleDeleteRowInnerTest"; string entityRowKey = "jobId-ThrottleDeleteRowInnerTest"; this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey); int targetStorageAccount = 1; TargetRTableWrapperApi <SampleRTableEntity> targetApi = this.rtableWrapper.DeleteRow; bool targetApiExpectedToFail = true; bool checkOriginalEntityUnchanged = true; bool checkStorageAccountsConsistent = false; DateTime httpManglerStartTime; this.SetupAndRunThrottleTableBehavior( entityPartitionKey, entityRowKey, targetStorageAccount, targetApi, targetApiExpectedToFail, checkOriginalEntityUnchanged, checkStorageAccountsConsistent, out httpManglerStartTime); if (targetApiExpectedToFail) { // After recovery from throttling, sleep some time to wait for entity to be unlocked, confirm that we can delete the row. this.SleepUntilRowLockHasExpired(httpManglerStartTime); this.ExecuteDeleteRowAndValidate(entityPartitionKey, entityRowKey); } else { // After recovery from throttling, confirm the entity is gone this.ExecuteReadRowAndValidateNotExist(entityPartitionKey, entityRowKey); } // Confirm we can create entity using the same partition and row keys again. this.ExecuteCreateRowAndValidate(entityPartitionKey, entityRowKey); }
public void A00TamperSkipDeleteRowHeadTest() { this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable); string entityPartitionKey = "jobType-TamperSkipDeleteRowHeadTest"; string entityRowKey = "jobId-TamperSkipDeleteRowHeadTest"; this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey); int targetStorageAccount = 0; TargetRTableWrapperApi <SampleRTableEntity> targetApi = this.rtableWrapper.DeleteRow; bool targetApiExpectedToFail = true; bool checkOriginalEntityUnchanged = false; bool checkStorageAccountsConsistent = false; int skipInitialiSessions = 2; this.SetupAndRunTamperTableBehavior( entityPartitionKey, entityRowKey, targetStorageAccount, targetApi, targetApiExpectedToFail, checkOriginalEntityUnchanged, checkStorageAccountsConsistent, skipInitialiSessions); if (targetApiExpectedToFail) { // After recovery from outage, confirm that we can delete the row. this.ExecuteDeleteRowAndValidate(entityPartitionKey, entityRowKey); } else { // After recovery from outage, confirm the entity is gone. this.ExecuteReadRowAndValidateNotExist(entityPartitionKey, entityRowKey); } // Confirm we can create entity using the same partition and row keys again. this.ExecuteCreateRowAndValidate(entityPartitionKey, entityRowKey); }
public void C00DelayDeleteRowTailTest() { this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable); string entityPartitionKey = "jobType-DelayDeleteRowTailTest"; string entityRowKey = "jobId-DelayDeleteRowTailTest"; this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey); int targetStorageAccount = this.actualStorageAccountsUsed.Count - 1; TargetRTableWrapperApi <SampleRTableEntity> targetApi = this.rtableWrapper.DeleteRow; bool targetApiExpectedToFail = false; int delayInMs = 3000; this.SetupAndRunDelayTableBehavior( entityPartitionKey, entityRowKey, targetStorageAccount, delayInMs, targetApi, targetApiExpectedToFail); if (targetApiExpectedToFail) { // After recovery from delay, confirm that we can delete the row. this.ExecuteDeleteRowAndValidate(entityPartitionKey, entityRowKey); } else { // After recovery from delay, confirm the entity is gone. this.ExecuteReadRowAndValidateNotExist(entityPartitionKey, entityRowKey); } // Confirm we can create entity using the same partition and row keys again. this.ExecuteCreateRowAndValidate(entityPartitionKey, entityRowKey); }
/// <summary> /// Helper function to set up an original entity and then run the **Throttle** Behavior against the specified storage account. /// </summary> /// <param name="entityPartitionKey"></param> /// <param name="entityRowKey"></param> /// <param name="targetStorageAccount">Specify which storage account to tamper with. 0 = Head; Count-1 = Tail</param> /// <param name="targetApi">Will call this RTable API while HttpMangler is enabled</param> /// <param name="targetApiExpectedToFail">True means the targetAPi is expected to fail when HttpMangler is enabled</param> /// <param name="checkOriginalEntityUnchanged">True means verify that the original entity (via GetRow()) is unchanged after this function.</param> /// <param name="checkStorageAccountsConsistent">True means verify that the individual storage accounts are consistent.</param> /// <param name="skipInitialSessions">Skip this many initial sessions. (Let them go through without being tampered)</param> protected void SetupAndRunDelayTableBehavior( string entityPartitionKey, string entityRowKey, int targetStorageAccount, TargetRTableWrapperApi<SampleRTableEntity> targetApi, bool targetApiExpectedToFail, bool checkOriginalEntityUnchanged, bool checkStorageAccountsConsistent, out DateTime httpManglerStartTime, int skipInitialSessions = 0) { Assert.IsTrue(0 <= targetStorageAccount && targetStorageAccount < this.actualStorageAccountsUsed.Count, "SetupAndRunDelayTableBehavior() is called with out-of-range targetStorageAccount={0}", targetStorageAccount); int index = this.actualStorageAccountsUsed[targetStorageAccount]; string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[index]; Console.WriteLine("SetupAndRunDelayTableBehavior(): accountNameToTamper={0} skipInitialSessions={1}", accountNameToTamper, skipInitialSessions); // Throttle behavior ProxyBehavior[] behaviors = new[] { TamperBehaviors.TamperAllResponsesIf( DelayResponse, AzureStorageSelectors.TableTraffic().IfUrlContains(repTable.TableName)) }; // // Arrange and Act: // SampleRTableEntity originalEntity = this.SetupAndRunHttpManglerBehaviorHelper( entityPartitionKey, entityRowKey, behaviors, targetApi, targetApiExpectedToFail, out httpManglerStartTime); // // Assert: // if (checkOriginalEntityUnchanged) { // Validate originalEntity remain unchanged. this.ExecuteReadRowAndValidate(entityPartitionKey, entityRowKey, originalEntity); } // For debug purposes: read from the Head and Tail accounts, and check for consistency this.ReadFromIndividualAccountsDirectly(entityPartitionKey, entityRowKey, checkStorageAccountsConsistent); }
protected void SetupAndRunThrottleTableBehavior( string entityPartitionKey, string entityRowKey, int targetStorageAccount, TargetRTableWrapperApi<SampleRTableEntity> targetApi, bool targetApiExpectedToFail, bool checkOriginalEntityUnchanged, bool checkStorageAccountsConsistent, int skipInitialSessions = 0) { DateTime httpManglerStartTime; this.SetupAndRunThrottleTableBehavior( entityPartitionKey, entityRowKey, targetStorageAccount, targetApi, targetApiExpectedToFail, checkOriginalEntityUnchanged, checkStorageAccountsConsistent, out httpManglerStartTime, skipInitialSessions); }
/// <summary> /// Helper function to set up an original entity and then run the **Delay** Behavior against the specified storage account. /// </summary> /// <param name="entityPartitionKey"></param> /// <param name="entityRowKey"></param> /// <param name="targetStorageAccount">Specify which storage account to tamper with. 0 = Head; Count-1 = Tail</param> /// <param name="delayInMs">This much delay will be introduced to transmissions to the specified storage account.</param> /// <param name="targetApi">Will call this RTable API while HttpMangler is enabled</param> /// <param name="targetApiExpectedToFail">True means the targetAPi is expected to fail when HttpMangler is enabled</param> protected void SetupAndRunDelayTableBehavior( string entityPartitionKey, string entityRowKey, int targetStorageAccount, int delayInMs, TargetRTableWrapperApi<SampleRTableEntity> targetApi, bool targetApiExpectedToFail) { Assert.IsTrue(0 <= targetStorageAccount && targetStorageAccount < this.actualStorageAccountsUsed.Count, "SetupAndRunDelayTableBehavior() is called with out-of-range targetStorageAccount={0}", targetStorageAccount); int index = this.actualStorageAccountsUsed[targetStorageAccount]; string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[index]; Console.WriteLine("SetupAndRunDelayTableBehavior(): accountNameToTamper={0}", accountNameToTamper); // Delay bahavior ProxyBehavior[] behaviors = new[] { DelayBehaviors.DelayAllRequestsIf( delayInMs, AzureStorageSelectors.TableTraffic().IfHostNameContains(accountNameToTamper + ".")) }; // // Arrange and Act: // DateTime httpManglerStartTime; SampleRTableEntity originalEntity = this.SetupAndRunHttpManglerBehaviorHelper( entityPartitionKey, entityRowKey, behaviors, targetApi, targetApiExpectedToFail, out httpManglerStartTime); // // Assert: // if (targetApiExpectedToFail) { // targetApi is expected to fail, so originalEntity should be untouched. this.ExecuteReadRowAndValidate(entityPartitionKey, entityRowKey, originalEntity); } else { // For debug purposes: read from the Head and Tail accounts, and check for consistency this.ReadFromIndividualAccountsDirectly(entityPartitionKey, entityRowKey, true); } }
/// <summary> /// Run the specified HttpMangler proxy behaviors for the specified Api. /// </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, TargetRTableWrapperApi<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); 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". /// </summary> /// <param name="entityPartitionKey"></param> /// <param name="entityRowKey"></param> /// <param name="behaviors">HttpMangler behaviors</param> /// <param name="targetApi">Will call this RTable API while HttpMangler is enabled</param> /// <param name="targetApiExpectedToFail">True means the targetAPi is expected to fail when HttpMangler is enabled</param> /// <param name="httpManglerStartTime">Output: time at which HttpMangler was enabled.</param> /// <returns>Original entity created</returns> private SampleRTableEntity SetupAndRunHttpManglerBehaviorHelper( string entityPartitionKey, string entityRowKey, ProxyBehavior[] behaviors, TargetRTableWrapperApi<SampleRTableEntity> targetApi, bool targetApiExpectedToFail, out 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; }