/// <summary> /// Verify recursively deleting a node that has a lot of immediate children /// </summary> /// <param name="childrenCount">Number of children to create</param> public async Task TestDeleteNodeWithManyChildren(int childrenCount = 10000) { var instrumentation = new TestRecursiveDeleterInstrumentation(); var deleter = new RecursiveDeleter(instrumentation, maxChildrenEnumerationCount: 10); using (var ringMaster = this.ConnectToRingMaster()) { string nodePath = $"{TestRecursiveDeleter.TestPrefix}/TestRecursiveDeleteNodeWithManyChildren_{Guid.NewGuid()}"; await ringMaster.Create(nodePath, null, null, CreateMode.Persistent); for (int i = 0; i < childrenCount; i++) { string childPath = $"{nodePath}/Child{i}"; await ringMaster.Create(childPath, null, null, CreateMode.Persistent); } int deletedCount = await deleter.Delete(ringMaster, nodePath, CancellationToken.None); await VerifyRingMasterException(RingMasterException.Code.Nonode, async() => await ringMaster.Exists(nodePath, watcher: null), $"{nodePath} should not exist"); Assert.AreEqual(childrenCount + 1, instrumentation.NodesDeletedCount); Assert.AreEqual(childrenCount + 1, deletedCount); Assert.AreEqual(childrenCount + 1, instrumentation.DeleteMultiSucceededOperationsCount); Assert.AreEqual(1, instrumentation.RecursiveDeleteSucceededCount); Assert.AreEqual(0, instrumentation.RecursiveDeleteFailedCount); } }
/// <summary> /// Verify that cancellation token is observed. /// </summary> public async Task TestCancelDelete() { var instrumentation = new TestRecursiveDeleterInstrumentation(); var deleter = new RecursiveDeleter(instrumentation); using (var ringMaster = this.ConnectToRingMaster()) { string nodePath = $"{TestRecursiveDeleter.TestPrefix}/TestCancelRecursiveDelete_{Guid.NewGuid()}"; await ringMaster.Create(nodePath, null, null, CreateMode.Persistent); var cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Cancel(); try { Trace.TraceInformation($"Attempting to delete {nodePath}"); await deleter.Delete(ringMaster, nodePath, cancellationTokenSource.Token); Assert.Fail("Delete should have thrown TaskCanceledException"); } catch (Exception ex) { Trace.TraceInformation($"Exception: {ex}"); } await ringMaster.Exists(nodePath, watcher : null); Assert.AreEqual(0, instrumentation.NodesDeletedCount); Assert.AreEqual(1, instrumentation.RecursiveDeleteFailedCount); } }
/// <summary> /// Verify that recursively deleting a non existent node fails. /// </summary> public async Task TestDeleteNonExistentNode() { var instrumentation = new TestRecursiveDeleterInstrumentation(); var deleter = new RecursiveDeleter(instrumentation); using (var ringMaster = this.ConnectToRingMaster()) { string nodePath = $"{TestRecursiveDeleter.TestPrefix}/TestRecursiveDeleteNonExistentNode_{Guid.NewGuid()}"; await VerifyRingMasterException( RingMasterException.Code.Nonode, async() => await deleter.Delete(ringMaster, nodePath, CancellationToken.None), $"Delete should not succeed for non-existent node {nodePath}"); Assert.AreEqual(0, instrumentation.NodesDeletedCount); } }
/// <summary> /// Verify that recursively deleting a node that has no children deletes the node. /// </summary> public async Task TestDeleteEmptyNode() { var instrumentation = new TestRecursiveDeleterInstrumentation(); var deleter = new RecursiveDeleter(instrumentation, maxChildrenEnumerationCount: 10); using (var ringMaster = this.ConnectToRingMaster()) { string nodePath = $"{TestRecursiveDeleter.TestPrefix}/TestRecursiveDeleteEmptyNode_{Guid.NewGuid()}"; await ringMaster.Create(nodePath, null, null, CreateMode.Persistent); int deletedCount = await deleter.Delete(ringMaster, nodePath, CancellationToken.None); await VerifyRingMasterException(RingMasterException.Code.Nonode, async() => await ringMaster.Exists(nodePath, watcher: null), $"{nodePath} should not exist"); Assert.AreEqual(1, instrumentation.NodesDeletedCount); Assert.AreEqual(1, deletedCount); } }
/// <summary> /// Verify failure to delete a node is handled properly. /// </summary> public async Task TestDeleteNodeFailure(int childrenCount = 5) { var instrumentation = new TestRecursiveDeleterInstrumentation(); var deleter = new RecursiveDeleter(instrumentation, maxChildrenEnumerationCount: 10); deleter.MaxDeleteBatchLength = 1; using (var ringMaster = this.ConnectToRingMaster()) { string nodePath = $"{TestRecursiveDeleter.TestPrefix}/TestRecursiveDeleteNodeFailure_{Guid.NewGuid()}"; await ringMaster.SetAuth(Digest1Identity); await ringMaster.Create(nodePath, null, null, CreateMode.Persistent); await ringMaster.SetAuth(Digest2Identity); await ringMaster.Create($"{nodePath}/Child0", null, new Acl[] { AllowDigest2, AllowDigest1Read }, CreateMode.Persistent); await ringMaster.SetAuth(Digest1Identity); for (int i = 1; i < childrenCount; i++) { await ringMaster.Create($"{nodePath}/Child{i}", null, new Acl[] { AllowDigest1 }, CreateMode.Persistent); } // We should be able to delete all the child nodes, // but not the parent node. await VerifyRingMasterException(RingMasterException.Code.Authfailed, async() => await deleter.Delete(ringMaster, nodePath, CancellationToken.None), $"{nodePath} should not be deleted"); Assert.AreEqual(childrenCount - 1, instrumentation.NodesDeletedCount); Assert.AreEqual(childrenCount - 1, instrumentation.DeleteMultiSucceededOperationsCount); Assert.AreEqual(1, instrumentation.DeleteMultiFailedOperationsCount); Assert.AreEqual(0, instrumentation.RecursiveDeleteSucceededCount); Assert.AreEqual(1, instrumentation.RecursiveDeleteFailedCount); } }