コード例 #1
0
        public void TableServiceContextTimeoutDuringSaveChangesNonBatchSync()
        {
            CloudTableClient    tableClient = GenerateCloudTableClient();
            TableServiceContext ctx         = tableClient.GetTableServiceContext();

            for (int m = 0; m < 100; m++)
            {
                BaseEntity ent = new BaseEntity("testpartition", m.ToString());
                ent.Randomize();
                ent.A = ent.RowKey;
                ctx.AddObject(currentTable.Name, ent);
            }

            OperationContext    opContext      = new OperationContext();
            TableRequestOptions requestOptions = new TableRequestOptions()
            {
                MaximumExecutionTime = TimeSpan.FromSeconds(5)
            };

            using (HttpMangler proxy = new HttpMangler(false,
                                                       new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName).SkipNSessions(10)) }))
            {
                try
                {
                    ctx.SaveChangesWithRetries(SaveChangesOptions.None, requestOptions, opContext);
                }
                catch (StorageException ex)
                {
                    Assert.AreEqual(ex.RequestInformation.HttpStatusCode, (int)HttpStatusCode.RequestTimeout);
                    Assert.AreEqual("The client could not finish the operation within specified timeout.", ex.Message);
                    Assert.IsTrue(ex.InnerException is TimeoutException);
                }
            }
        }
コード例 #2
0
        public void QueueGetACLCancellation()
        {
            CloudQueue queue = DefaultQueueClient.GetQueueReference(GenerateNewQueueName());

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.QueueTraffic().IfHostNameContains(DefaultQueueClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => queue.BeginGetPermissions((QueueRequestOptions)options, opContext, callback, state),
                                                        (res) => queue.EndGetPermissions(res));
        }
コード例 #3
0
        public void TableGetACLCancellation()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();

            CloudTable tbl = tableClient.GetTableReference(GenerateRandomTableName());

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => tbl.BeginGetPermissions((TableRequestOptions)options, opContext, callback, state),
                                                        (res) => tbl.EndGetPermissions(res));
        }
コード例 #4
0
        public void TableServiceContextTimeoutDuringSaveChangesNonBatchAPM()
        {
            CloudTableClient    tableClient = GenerateCloudTableClient();
            TableServiceContext ctx         = tableClient.GetTableServiceContext();

            for (int m = 0; m < 100; m++)
            {
                BaseEntity ent = new BaseEntity("testpartition", m.ToString());
                ent.Randomize();
                ent.A = ent.RowKey;
                ctx.AddObject(currentTable.Name, ent);
            }

            OperationContext    opContext      = new OperationContext();
            TableRequestOptions requestOptions = new TableRequestOptions()
            {
                MaximumExecutionTime = TimeSpan.FromSeconds(5)
            };

            using (HttpMangler proxy = new HttpMangler(false,
                                                       new[] { DelayBehaviors.DelayAllRequestsIf(2000, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName).SkipNSessions(10)) }))
            {
                try
                {
                    using (ManualResetEvent evt = new ManualResetEvent(false))
                    {
                        IAsyncResult result = ctx.BeginSaveChangesWithRetries(SaveChangesOptions.None, requestOptions, opContext,
                                                                              (res) =>
                        {
                            result = res;
                            evt.Set();
                        }, null);

                        evt.WaitOne();

                        ctx.EndSaveChangesWithRetries(result);
                    }

                    ctx.SaveChangesWithRetries(SaveChangesOptions.None, requestOptions, opContext);
                }
                catch (StorageException ex)
                {
                    Assert.AreEqual(ex.RequestInformation.HttpStatusCode, (int)HttpStatusCode.RequestTimeout);
                    Assert.AreEqual(ex.Message, "The operation timed out.");
                    Assert.IsTrue(ex.InnerException is TimeoutException);
                }
            }
        }
コード例 #5
0
        public void TableOperationCancellation()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();

            DynamicTableEntity insertEntity = new DynamicTableEntity("insert test", "foo");

            for (int m = 0; m < 20; m++)
            {
                insertEntity.Properties.Add("prop" + m.ToString(), new EntityProperty(new byte[50 * 1024]));
            }

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => currentTable.BeginExecute(TableOperation.Insert(insertEntity), (TableRequestOptions)options, opContext, callback, state),
                                                        (res) => currentTable.EndExecute(res));
        }
コード例 #6
0
        public void TableTestSaveChangesCancellationNonBatch()
        {
            CloudTableClient    tableClient = GenerateCloudTableClient();
            TableServiceContext ctx         = tableClient.GetTableServiceContext();

            for (int m = 0; m < 100; m++)
            {
                // Insert Entity
                ComplexEntity insertEntity = new ComplexEntity("insert test", m.ToString());
                ctx.AddObject(currentTable.Name, insertEntity);
            }

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => ctx.BeginSaveChangesWithRetries(SaveChangesOptions.None, (TableRequestOptions)options, opContext, callback, state),
                                                        (res) => ctx.EndSaveChangesWithRetries(res));
        }
コード例 #7
0
        public void QueueSetACLCancellation()
        {
            CloudQueue queue = DefaultQueueClient.GetQueueReference(GenerateNewQueueName());

            QueuePermissions permissions = new QueuePermissions();

            permissions.SharedAccessPolicies.Add(Guid.NewGuid().ToString(), new SharedAccessQueuePolicy()
            {
                SharedAccessStartTime  = DateTimeOffset.Now - TimeSpan.FromHours(1),
                SharedAccessExpiryTime = DateTimeOffset.Now + TimeSpan.FromHours(1),
                Permissions            = SharedAccessQueuePermissions.Add | SharedAccessQueuePermissions.ProcessMessages | SharedAccessQueuePermissions.Read | SharedAccessQueuePermissions.Update
            });

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.QueueTraffic().IfHostNameContains(DefaultQueueClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => queue.BeginSetPermissions(permissions, (QueueRequestOptions)options, opContext, callback, state),
                                                        queue.EndSetPermissions);
        }
コード例 #8
0
        public void CloudBlobContainerSetMetadataAPMCancel()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                container.Metadata.Add("key1", "value1");

                TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                            new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, AzureStorageSelectors.BlobTraffic().IfHostNameContains(container.ServiceClient.Credentials.AccountName)) },
                                                            (options, opContext, callback, state) => container.BeginSetMetadata(null, (BlobRequestOptions)options, opContext, callback, state),
                                                            container.EndSetMetadata);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
コード例 #9
0
        public void TableSetACLCancellation()
        {
            CloudTableClient tableClient = GenerateCloudTableClient();

            CloudTable tbl = tableClient.GetTableReference(GenerateRandomTableName());

            TablePermissions perms = new TablePermissions();

            // Add a policy, check setting and getting.
            perms.SharedAccessPolicies.Add(Guid.NewGuid().ToString(), new SharedAccessTablePolicy
            {
                Permissions            = SharedAccessTablePermissions.Query,
                SharedAccessStartTime  = DateTimeOffset.Now - TimeSpan.FromHours(1),
                SharedAccessExpiryTime = DateTimeOffset.Now + TimeSpan.FromHours(1)
            });

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => tbl.BeginSetPermissions(perms, (TableRequestOptions)options, opContext, callback, state),
                                                        tbl.EndSetPermissions);
        }
コード例 #10
0
        public void TableTestTableQueryCancellation()
        {
            CloudTableClient    tableClient = GenerateCloudTableClient();
            TableBatchOperation batch       = new TableBatchOperation();

            for (int m = 0; m < 100; m++)
            {
                // Insert Entity
                DynamicTableEntity insertEntity = new DynamicTableEntity("insert test", m.ToString());
                insertEntity.Properties.Add("prop" + m.ToString(), new EntityProperty(new byte[30 * 1024]));
                batch.Insert(insertEntity);
            }

            currentTable.ExecuteBatch(batch);
            TableQuery query = new TableQuery().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "insert test"));

            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => currentTable.BeginExecuteQuerySegmented(query, null, (TableRequestOptions)options, opContext, callback, state),
                                                        (res) => currentTable.EndExecuteQuerySegmented(res));
        }
コード例 #11
0
        public void TableTestSegmentedQueryCancellation()
        {
            CloudTableClient    tableClient = GenerateCloudTableClient();
            TableServiceContext ctx         = tableClient.GetTableServiceContext();

            for (int m = 0; m < 100; m++)
            {
                // Insert Entity
                ComplexEntity insertEntity = new ComplexEntity("insert test", m.ToString());
                ctx.AddObject(currentTable.Name, insertEntity);
            }
            ctx.SaveChangesWithRetries();

            TableServiceQuery <BaseEntity> query = (from ent in ctx.CreateQuery <BaseEntity>(currentTable.Name)
                                                    select ent).AsTableServiceQuery(ctx);


            TestHelper.ExecuteAPMMethodWithCancellation(4000,
                                                        new[] { DelayBehaviors.DelayAllRequestsIf(4000 * 3, XStoreSelectors.TableTraffic().IfHostNameContains(tableClient.Credentials.AccountName)) },
                                                        (options, opContext, callback, state) => query.BeginExecuteSegmented(null, (TableRequestOptions)options, opContext, callback, state),
                                                        (res) => query.EndExecuteSegmented(res));
        }
コード例 #12
0
        public void TxnViewExpiresAndViewIdHasChanged()
        {
            // Insert an entry
            string entityPartitionKey = "jobType-ReplaceWhenTxnViewExpires";
            string entityRowKey       = "jobType-ReplaceWhenTxnViewExpires";

            this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey);

            Console.WriteLine("Inserting entry ...");
            var entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, "insert message");

            this.rtableWrapper.InsertRow(entry);

            // Retrieve the config ...
            ReplicatedTableConfiguration    config;
            ReplicatedTableQuorumReadResult readStatus = this.configurationService.RetrieveConfiguration(out config);

            Assert.IsTrue(readStatus.Code == ReplicatedTableQuorumReadCode.Success);

            // Reconfigure RTable config with a short LeaseDuration
            int leaseDurationInSec = 3;

            config.LeaseDuration = leaseDurationInSec;
            this.configurationService.UpdateConfiguration(config);

            string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[0];

            Console.WriteLine("RunHttpManglerBehaviorHelper(): accountNameToTamper={0}", accountNameToTamper);

            // Delay behavior
            ProxyBehavior[] behaviors = new[]
            {
                DelayBehaviors.DelayAllResponsesIf(
                    1,
                    (session =>
                {
                    var body = session.GetRequestBodyAsString();

                    // Delay lock of the Head response enough so the txView expires ...
                    // And, upload a new config with a new viewId
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        body.Contains("\"_rtable_Operation\":\"Replace\"") &&
                        body.Contains("\"_rtable_RowLock\":true"))
                    {
                        // Upload a new config with a new ViewId
                        View view = this.configurationService.GetTableView(this.repTable.TableName);
                        config.GetView(view.Name).ViewId++;
                        this.configurationService.UpdateConfiguration(config, false);

                        // ensure txView expires
                        Thread.Sleep(2 * leaseDurationInSec * 1000);
                        return(true);
                    }

                    return(false);
                })),
            };

            // Launch an Update
            using (new HttpMangler(false, behaviors))
            {
                try
                {
                    entry         = this.rtableWrapper.ReadEntity(entityPartitionKey, entityRowKey);
                    entry.Message = "update message";

                    var            table            = new ReplicatedTable(this.repTable.TableName, this.configurationService);
                    TableOperation replaceOperation = TableOperation.Replace(entry);

                    // Get a snapshot of txView before transaction starts ...
                    View viewBeforeTx = this.configurationService.GetTableView(this.repTable.TableName);

                    // Transaction will get delayed 2*LeaseDuration sec. and Config/ViewId will be changed
                    TableResult replaceResult = table.Execute(replaceOperation);

                    Assert.IsTrue(viewBeforeTx.IsExpired(), "txView expected to expire!");
                    Assert.AreNotEqual(this.configurationService.GetTableView(this.repTable.TableName).ViewId, viewBeforeTx.ViewId, "ViewId should have changed!");

                    Assert.IsNotNull(replaceResult, "upsertResult = null");
                    Assert.AreNotEqual((int)HttpStatusCode.NoContent, replaceResult.HttpStatusCode, "upsertResult.HttpStatusCode mismatch");
                }
                catch (ReplicatedTableStaleViewException ex)
                {
                    // ValidateTxnView is called form everywhere ... we may endup here too
                    switch (ex.ErrorCode)
                    {
                    case ReplicatedTableViewErrorCodes.ViewIdChanged:
                        break;

                    default:
                        Console.WriteLine(ex);
                        Assert.IsTrue(false);
                        break;
                    }
                }
            }
        }
コード例 #13
0
        public void A00InsertOrReplaceCallConflictingWithDeleteOnTheHead()
        {
            this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable);

            string entityPartitionKey = "jobType-DelayInsertOrReplaceWhileDelete";
            string entityRowKey       = "jobType-DelayInsertOrReplaceWhileDelete";

            this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey);

            // Insert one entry
            Console.WriteLine("Inserting entry ...");
            var entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, "insert message");

            this.rtableWrapper.InsertRow(entry);

            // 1 - Launch an Upsert task in wait mode ...
            bool deleteLockedHead = false;

            TableResult upsertResult = null;
            var         upsertTask   = Task.Run(() =>
            {
                while (!deleteLockedHead)
                {
                    Thread.Sleep(5);
                }

                try
                {
                    entry     = new SampleRTableEntity(entityPartitionKey, entityRowKey, "upsert message");
                    var table = new ReplicatedTable(this.repTable.TableName, this.configurationService);

                    TableOperation upserOperation = TableOperation.InsertOrReplace(entry);

                    Console.WriteLine("Upsert started ...");
                    upsertResult = table.Execute(upserOperation);
                    Console.WriteLine("Upsert completed with HttpStatus={0}", upsertResult == null ? "NULL" : upsertResult.HttpStatusCode.ToString());
                }
                catch (AggregateException ex)
                {
                    Console.WriteLine(ex);
                }
            });


            string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[0];

            Console.WriteLine("RunHttpManglerBehaviorHelper(): accountNameToTamper={0}", accountNameToTamper);

            int delayInMs = 5;

            // Delay behavior
            ProxyBehavior[] behaviors = new[]
            {
                DelayBehaviors.DelayAllResponsesIf(
                    delayInMs,
                    (session =>
                {
                    var body = session.GetRequestBodyAsString();

                    Console.WriteLine(body);

                    // Delete locking the head response
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        body.Contains("\"_rtable_Operation\":\"Replace\"") &&
                        body.Contains("\"_rtable_RowLock\":true") &&
                        body.Contains("\"_rtable_Tombstone\":true"))
                    {
                        // Signal upsert we locked the head, so it can continue ...
                        deleteLockedHead = true;
                        return(true);
                    }

                    return(false);
                })),
            };

            // Launch a delete
            using (new HttpMangler(false, behaviors))
            {
                try
                {
                    var table = new ReplicatedTable(this.repTable.TableName, this.configurationService);

                    // Retrieve entity
                    TableOperation retrieveOperation = TableOperation.Retrieve <SampleRTableEntity>(entry.PartitionKey, entry.RowKey);
                    TableResult    retrieveResult    = table.Execute(retrieveOperation);

                    Assert.IsNotNull(retrieveResult, "retrieveResult = null");
                    Assert.AreEqual((int)HttpStatusCode.OK, retrieveResult.HttpStatusCode, "retrieveResult.HttpStatusCode mismatch");
                    Assert.IsNotNull((SampleRTableEntity)retrieveResult.Result, "Retrieve: customer = null");


                    // Delete entity
                    TableOperation deleteOperation = TableOperation.Delete((SampleRTableEntity)retrieveResult.Result);
                    TableResult    deleteResult    = table.Execute(deleteOperation);

                    Assert.IsNotNull(deleteResult, "deleteResult = null");
                    Assert.AreEqual((int)HttpStatusCode.NoContent, deleteResult.HttpStatusCode, "deleteResult.HttpStatusCode mismatch");
                }
                catch (AggregateException ex)
                {
                    Console.WriteLine(ex);
                }
            }

            // wait on upsert to finish ...
            upsertTask.Wait();

            // Upsert suceeded?
            Assert.AreEqual((int)HttpStatusCode.NoContent, upsertResult.HttpStatusCode, "Upsert expected to suceed!");
            SampleRTableEntity upsertedEntity = this.rtableWrapper.ReadEntity(entityPartitionKey, entityRowKey);

            Assert.NotNull(upsertedEntity, "upsert should succeed");
            Assert.AreEqual(upsertedEntity.Message, "upsert message", "upsert should succeeded");
        }
コード例 #14
0
        public void A00TwoInsertOrReplaceCallsConflictingOnTheHead()
        {
            this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable);

            string entityPartitionKey = "jobType-DelayInsertOrReplaceRowHeadTest";
            string entityRowKey       = "jobId-DelayInsertOrReplaceRowHeadTest";

            this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey);

            // Insert one entry
            Console.WriteLine("Inserting entry ...");
            var entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, "insert message");

            this.rtableWrapper.InsertRow(entry);

            string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[0];

            Console.WriteLine("RunHttpManglerBehaviorHelper(): accountNameToTamper={0}", accountNameToTamper);

            int  delayInMs = 3000;
            bool firstWritterInitiatingCommit  = false;
            bool secondWritterTriedLockingHead = false;

            // Delay behavior
            ProxyBehavior[] behaviors = new[]
            {
                // Writter-1 tampering
                TamperBehaviors.TamperAllRequestsIf(
                    (session =>
                {
                    int iter = 0;

                    // Signal Writter-2
                    firstWritterInitiatingCommit = true;

                    // Blobk commit to head ... until Writter-2 try to lock the head
                    while (!secondWritterTriedLockingHead)
                    {
                        Console.WriteLine("Writter-1 waiting on Writter-2 to try to lock the Head (#{0})", iter);
                        Thread.Sleep(delayInMs);

                        if (++iter > 10)
                        {
                            break;
                        }
                    }
                }),
                    (session =>
                {
                    var body = session.GetRequestBodyAsString();

                    // Writter-1 committing to head
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        body.Contains("\"_rtable_Operation\":\"Replace\"") &&
                        body.Contains("\"_rtable_RowLock\":false") &&
                        body.Contains("\"Message\":\"upsert message 0\"")
                        )
                    {
                        return(true);
                    }

                    return(false);
                })),

                // Writter-2 tampering
                TamperBehaviors.TamperAllRequestsIf(
                    (session =>
                {
                    // Block till Writter-1 issues a commit to head
                    while (!firstWritterInitiatingCommit)
                    {
                        Console.WriteLine("Writter-2 waiting on Writter-1 to issue a commit to head");
                        Thread.Sleep(delayInMs);
                    }
                }),
                    (session =>
                {
                    var body = session.GetRequestBodyAsString();

                    // Writter-2 locking the head
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        body.Contains("\"_rtable_Operation\":\"Replace\"") &&
                        body.Contains("\"_rtable_RowLock\":true") &&
                        body.Contains("\"Message\":\"upsert message 1\"")
                        )
                    {
                        return(true);
                    }

                    return(false);
                })),

                // Delay Writter-2 lock-to-the-head's response, so Writter-1 can continue with its commit.
                DelayBehaviors.DelayAllResponsesIf(
                    delayInMs,
                    (session =>
                {
                    var body = session.GetRequestBodyAsString();

                    // Writter-2 locking the head response
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("PUT") &&
                        body.Contains("\"_rtable_Operation\":\"Replace\"") &&
                        body.Contains("\"_rtable_RowLock\":true") &&
                        body.Contains("\"Message\":\"upsert message 1\"")
                        )
                    {
                        // Signal Writter-1 so it can continue with commit to head
                        secondWritterTriedLockingHead = true;
                        return(true);
                    }

                    return(false);
                })),
            };

            // Launch 2 concurrent Upserts
            var results = new TableResult[2];

            using (new HttpMangler(false, behaviors))
            {
                Parallel.For(0, 2, (index) =>
                {
                    entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, string.Format("upsert message {0}", index));

                    try
                    {
                        var table = new ReplicatedTable(this.repTable.TableName, this.configurationService);

                        TableOperation operation = TableOperation.InsertOrReplace(entry);
                        results[index]           = table.Execute(operation);
                    }
                    catch (AggregateException ex)
                    {
                        Console.WriteLine(ex);
                    }
                });
            }

            // Writter-1 suceed?
            Assert.AreEqual((int)HttpStatusCode.NoContent, results[0].HttpStatusCode, "Writter-1 expected to suceed!");

            // Writter-2 suceeded?
            Assert.AreEqual((int)HttpStatusCode.NoContent, results[1].HttpStatusCode, "Writter-2 expected to suceed!");

            // Writter-2 upsert succeeded
            SampleRTableEntity upsertedEntity = this.rtableWrapper.ReadEntity(entityPartitionKey, entityRowKey);

            Assert.NotNull(upsertedEntity, "Writter-2 upsert succeeded");
            Assert.AreEqual(upsertedEntity.Message, string.Format("upsert message {0}", 1), "Writter-2 upsert succeeded");
        }
コード例 #15
0
        public void A00DelayTwoConflictingInsertOrReplaceCalls()
        {
            this.rtableWrapper = RTableWrapperForSampleRTableEntity.GetRTableWrapper(this.repTable);

            string entityPartitionKey = "jobType-DelayInsertOrReplaceRowHeadTest";
            string entityRowKey       = "jobId-DelayInsertOrReplaceRowHeadTest";

            this.ForceDeleteEntryFromStorageTablesDirectly(entityPartitionKey, entityRowKey);

            string accountNameToTamper = this.rtableTestConfiguration.StorageInformation.AccountNames[0];

            Console.WriteLine("RunHttpManglerBehaviorHelper(): accountNameToTamper={0}", accountNameToTamper);

            int  delayInMs              = 3000;
            int  insertRequestCount     = 0;
            int  conflictResponseCount  = 0;
            bool secondUpsertConflicted = false;
            int  failedCallIndex        = -1;

            // Delay behavior
            ProxyBehavior[] behaviors = new[]
            {
                // Delay Insert calls so they end up conflicting
                TamperBehaviors.TamperAllRequestsIf(
                    (session =>
                {
                    Interlocked.Increment(ref insertRequestCount);

                    while (insertRequestCount != 2)
                    {
                        Console.WriteLine("insertRequestCount={0}. Waiting on count to reach 2 ...", insertRequestCount);
                        Thread.Sleep(delayInMs);
                    }
                }),
                    (session =>
                {
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.HTTPMethodIs("POST") &&
                        session.GetRequestBodyAsString().Contains("\"_rtable_Operation\":\"Insert\""))
                    {
                        return(true);
                    }

                    return(false);
                })),

                // Delay conflict response
                DelayBehaviors.DelayAllResponsesIf(
                    delayInMs,
                    (session =>
                {
                    if (session.hostname.Contains(accountNameToTamper + ".") &&
                        session.GetRequestBodyAsString().Contains("\"_rtable_Operation\":\"Insert\""))
                    {
                        if (session.responseCode == (int)HttpStatusCode.Conflict)
                        {
                            Interlocked.Increment(ref conflictResponseCount);

                            return(true);
                        }
                    }

                    return(false);
                })),
            };

            using (new HttpMangler(false, behaviors))
            {
                Parallel.For(0, 2, (index) =>
                {
                    var entry = new SampleRTableEntity(entityPartitionKey, entityRowKey, string.Format("upsert message {0}", index));
                    try
                    {
                        this.rtableWrapper.InsertOrReplaceRow(entry);
                    }
                    catch (RTableConflictException)
                    {
                        if (secondUpsertConflicted)
                        {
                            // should never reach here
                            throw;
                        }

                        // That's possible, but that's the Replace step of upsert which conflicted with ongoing write
                        // can't do anything, client should retry on conflict
                        secondUpsertConflicted = true;
                    }
                });
            }

            // got 2 inserts?
            Assert.AreEqual(2, insertRequestCount, "Two insert calls expected!");

            // got one conflict?
            Assert.AreEqual(1, conflictResponseCount, "One conflict response expected!");

            // at least one upsert would have succeeded
            SampleRTableEntity upsertedEntity = this.rtableWrapper.ReadEntity(entityPartitionKey, entityRowKey);

            Assert.NotNull(upsertedEntity, "at least one upsert should have succeeded");

            // second upsert failed?
            if (secondUpsertConflicted)
            {
                Assert.AreEqual(1, upsertedEntity._rtable_Version, "one upsert succeeded so version should be = 1");
                Assert.AreEqual(upsertedEntity.Message, string.Format("upsert message {0}", (1 - failedCallIndex)));
            }
            else
            {
                Assert.AreEqual(2, upsertedEntity._rtable_Version, "both upserts succeeded so version should be = 2");
            }


            // After recovery from delay, confirm that we can update the row.
            //this.ExecuteReplaceRowAndValidate(entityPartitionKey, entityRowKey);
        }