Skip to content

Commit

Permalink
SDK 3.39.1: Adds version bump and changelog. (#4437)
Browse files Browse the repository at this point in the history
* SDK 3.39.1/3.40.0-preview.1: Adds version bump and changelog. (#4430)

* SDK 3.39.1/3.40.0-preview.1: Adds version bump and changelog.

* Update changelog.md

Co-authored-by: Matias Quaranta <ealsur@users.noreply.github.com>

---------

Co-authored-by: Matias Quaranta <ealsur@users.noreply.github.com>
Co-authored-by: Sourabh Jain <sourabhjain@microsoft.com>

* ChangeFeedProcessor: Fixes ArgumentException when dealing with Legacy lease incremental documents that do not have a Mode property (#4426)

* fix for 4423

* fix comment

* some recommendation changes

---------

Co-authored-by: Matias Quaranta <ealsur@users.noreply.github.com>
Co-authored-by: Sourabh Jain <sourabhjain@microsoft.com>
  • Loading branch information
3 people committed Apr 18, 2024
1 parent 5e6232d commit 8a59688
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 52 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ClientOfficialVersion>3.39.0</ClientOfficialVersion>
<ClientOfficialVersion>3.39.1</ClientOfficialVersion>
<ClientPreviewVersion>3.40.0</ClientPreviewVersion>
<ClientPreviewSuffixVersion>preview.0</ClientPreviewSuffixVersion>
<ClientPreviewSuffixVersion>preview.1</ClientPreviewSuffixVersion>
<DirectVersion>3.33.1</DirectVersion>
<EncryptionOfficialVersion>2.0.4</EncryptionOfficialVersion>
<EncryptionPreviewVersion>2.1.0</EncryptionPreviewVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,37 +85,33 @@ internal abstract class DocumentServiceLeaseManager

DocumentServiceLease documentServiceLease = documentServiceLeases[0];

// Mode attribute exists on lease document, but it is not set. legacy is always LatestVersion because
// AllVersionsAndDeletes does not exist. There should not be any legacy lease documents that are
// AllVersionsAndDeletes. If the ChangeFeedProcessor's mode is not legacy, an exception should thrown.
// If the ChangeFeedProcessor mode is not the mode in the lease document, an exception should be thrown.

bool shouldThrowException = this.VerifyChangeFeedProcessorMode(
changeFeedMode:
string.IsNullOrEmpty(documentServiceLease.Mode)
? ChangeFeedMode.LatestVersion
: changeFeedLeaseOptionsMode,
leaseChangeFeedMode: documentServiceLease.Mode,
normalizedProcessorChangeFeedMode: out string normalizedProcessorChangeFeedMode);

// If shouldThrowException is true, throw the exception.

if (shouldThrowException)
{
throw new ArgumentException(message: $"Switching {nameof(ChangeFeedMode)} {documentServiceLease.Mode} to {normalizedProcessorChangeFeedMode} is not allowed.");
}
this.VerifyChangeFeedProcessorMode(
changeFeedMode: changeFeedLeaseOptionsMode,
leaseChangeFeedMode: documentServiceLease.Mode);
}

private bool VerifyChangeFeedProcessorMode(
/// <summary>
/// Mode attribute exists on lease document, but it is not set. Legacy is always LatestVersion/IncrementalFeed
/// because AllVersionsAndDeletes does not exist. There should not be any legacy lease documents that are
/// AllVersionsAndDeletes. If the ChangeFeedProcessor's mode is not legacy, an exception should thrown.
/// If the ChangeFeedProcessor mode is not the mode in the lease document, an exception should be thrown.
/// </summary>
/// <param name="changeFeedMode">The current change feed mode.</param>
/// <param name="leaseChangeFeedMode">The change feed mode on the lease document.</param>
private void VerifyChangeFeedProcessorMode(
ChangeFeedMode changeFeedMode,
string leaseChangeFeedMode,
out string normalizedProcessorChangeFeedMode)
string leaseChangeFeedMode)
{
normalizedProcessorChangeFeedMode = changeFeedMode == ChangeFeedMode.AllVersionsAndDeletes
leaseChangeFeedMode ??= HttpConstants.A_IMHeaderValues.IncrementalFeed;

string normalizedProcessorChangeFeedMode = changeFeedMode == ChangeFeedMode.AllVersionsAndDeletes
? HttpConstants.A_IMHeaderValues.FullFidelityFeed
: HttpConstants.A_IMHeaderValues.IncrementalFeed;

return string.Compare(leaseChangeFeedMode, normalizedProcessorChangeFeedMode, StringComparison.OrdinalIgnoreCase) != 0;
if (string.Compare(leaseChangeFeedMode, normalizedProcessorChangeFeedMode, StringComparison.OrdinalIgnoreCase) != 0)
{
throw new ArgumentException(message: $"Switching {nameof(ChangeFeedMode)} {leaseChangeFeedMode} to {normalizedProcessorChangeFeedMode} is not allowed.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests.ChangeFeed
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.ChangeFeed.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

[TestClass]
[TestCategory("ChangeFeedProcessor")]
Expand Down Expand Up @@ -107,8 +108,6 @@ public async Task WhenADocumentIsCreatedThenUpdatedThenDeletedTestsAsync()
Assert.IsTrue(condition: createChange.Metadata.Lsn < replaceChange.Metadata.Lsn, message: "The create operation must happen before the replace operation.");
Assert.IsTrue(condition: createChange.Metadata.Lsn < replaceChange.Metadata.Lsn, message: "The replace operation must happen before the delete operation.");
Debug.WriteLine("Assertions completed.");
return Task.CompletedTask;
})
.WithInstanceName(Guid.NewGuid().ToString())
Expand All @@ -117,9 +116,6 @@ public async Task WhenADocumentIsCreatedThenUpdatedThenDeletedTestsAsync()
{
exception = error.InnerException;
Debug.WriteLine("WithErrorNotification");
Debug.WriteLine(error.ToString());
return Task.CompletedTask;
})
.Build();
Expand Down Expand Up @@ -176,11 +172,46 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed));

Debug.WriteLine(exception.ToString());

Assert.AreEqual(expected: "Switching ChangeFeedMode Incremental Feed to Full-Fidelity Feed is not allowed.", actual: exception.Message);
}


/// <summary>
/// This is based on an issue located at <see href="https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4308"/>.
/// </summary>
[TestMethod]
[Owner("philipthomas-MSFT")]
[Description("Scenario: For Legacy lease documents with no Mode property, When ChangeFeedMode on ChangeFeedProcessor, switches from LatestVersion to AllVersionsAndDeletes," +
"an exception is expected. LatestVersion's WithStartFromBeginning can be set, or not set.")]
[DataRow(false)]
[DataRow(true)]
public async Task WhenLegacyLatestVersionSwitchToAllVersionsAndDeletesExpectsAexceptionTestAsync(bool withStartFromBeginning)
{
ContainerInternal monitoredContainer = await this.CreateMonitoredContainer(ChangeFeedMode.LatestVersion);
ManualResetEvent allDocsProcessed = new(false);

await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.BuildChangeFeedProcessorWithLatestVersionAsync(
monitoredContainer: monitoredContainer,
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed,
withStartFromBeginning: withStartFromBeginning);

// Read lease documents, remove the Mode, and update the lease documents, so that it mimics a legacy lease document.

await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.RevertLeaseDocumentsToLegacyWithNoMode(
leaseContainer: this.LeaseContainer,
leaseDocumentCount: 2);

ArgumentException exception = await Assert.ThrowsExceptionAsync<ArgumentException>(
() => GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.BuildChangeFeedProcessorWithAllVersionsAndDeletesAsync(
monitoredContainer: monitoredContainer,
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed));

Debug.WriteLine("Assertions completed.");
Assert.AreEqual(expected: "Switching ChangeFeedMode Incremental Feed to Full-Fidelity Feed is not allowed.", actual: exception.Message);
}

/// <summary>
Expand Down Expand Up @@ -211,11 +242,7 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
allDocsProcessed: allDocsProcessed,
withStartFromBeginning: withStartFromBeginning));

Debug.WriteLine(exception.ToString());

Assert.AreEqual(expected: "Switching ChangeFeedMode Full-Fidelity Feed to Incremental Feed is not allowed.", actual: exception.Message);

Debug.WriteLine("Assertions completed.");
}

/// <summary>
Expand Down Expand Up @@ -243,8 +270,6 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
monitoredContainer: monitoredContainer,
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed);

Debug.WriteLine("No exceptions occurred.");
}
catch
{
Expand Down Expand Up @@ -281,15 +306,87 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed,
withStartFromBeginning: withStartFromBeginning);

Debug.WriteLine("No exceptions occurred.");
}
catch
{
Assert.Fail("An exception occurred when one was not expceted."); ;
}
}

/// <summary>
/// This is based on an issue located at <see href="https://github.com/Azure/azure-cosmos-dotnet-v3/issues/4423"/>.
/// </summary>
[TestMethod]
[Owner("philipthomas-MSFT")]
[Description("Scenario: For Legacy lease documents with no Mode property, When ChangeFeedMode on ChangeFeedProcessor " +
"does not switch, LatestVersion, no exception is expected. LatestVersion's WithStartFromBeginning can be set, or not set.")]
[DataRow(false)]
[DataRow(true)]
public async Task WhenLegacyNoSwitchLatestVersionDoesNotExpectAnExceptionTestAsync(bool withStartFromBeginning)
{
ContainerInternal monitoredContainer = await this.CreateMonitoredContainer(ChangeFeedMode.LatestVersion);
ManualResetEvent allDocsProcessed = new(false);

await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.BuildChangeFeedProcessorWithLatestVersionAsync(
monitoredContainer: monitoredContainer,
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed,
withStartFromBeginning: withStartFromBeginning);

// Read lease documents, remove the Mode, and update the lease documents, so that it mimics a legacy lease document.

await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.RevertLeaseDocumentsToLegacyWithNoMode(
leaseContainer: this.LeaseContainer,
leaseDocumentCount: 2);

await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
.BuildChangeFeedProcessorWithLatestVersionAsync(
monitoredContainer: monitoredContainer,
leaseContainer: this.LeaseContainer,
allDocsProcessed: allDocsProcessed,
withStartFromBeginning: withStartFromBeginning);
}

private static async Task RevertLeaseDocumentsToLegacyWithNoMode(
Container leaseContainer,
int leaseDocumentCount)
{
FeedIterator iterator = leaseContainer.GetItemQueryStreamIterator(
queryText: "SELECT * FROM c",
continuationToken: null);

List<JObject> leases = new List<JObject>();
while (iterator.HasMoreResults)
{
using (ResponseMessage responseMessage = await iterator.ReadNextAsync().ConfigureAwait(false))
{
responseMessage.EnsureSuccessStatusCode();
leases.AddRange(CosmosFeedResponseSerializer.FromFeedResponseStream<JObject>(
serializerCore: CosmosContainerExtensions.DefaultJsonSerializer,
streamWithServiceEnvelope: responseMessage.Content));
}
}

int counter = 0;

foreach (JObject lease in leases)
{
if (!lease.ContainsKey("Mode"))
{
continue;
}

counter++;
lease.Remove("Mode");

_ = await leaseContainer.UpsertItemAsync(item: lease);
}

Assert.AreEqual(expected: leaseDocumentCount, actual: counter);
}

private static async Task BuildChangeFeedProcessorWithLatestVersionAsync(
ContainerInternal monitoredContainer,
Container leaseContainer,
Expand All @@ -307,9 +404,6 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
{
exception = error.InnerException;
Debug.WriteLine("WithErrorNotification");
Debug.WriteLine(error.ToString());
return Task.CompletedTask;
});

Expand All @@ -318,7 +412,6 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
processorBuilder.WithStartFromBeginning();
}


ChangeFeedProcessor processor = processorBuilder.Build();
Interlocked.Exchange(ref latestVersionProcessorAtomic, processor);

Expand Down Expand Up @@ -349,9 +442,6 @@ await GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests
{
exception = error.InnerException;
Debug.WriteLine("WithErrorNotification");
Debug.WriteLine(error.ToString());
return Task.FromResult(exception);
});

Expand All @@ -376,8 +466,6 @@ private async Task<ContainerInternal> CreateMonitoredContainer(ChangeFeedMode ch

if (changeFeedMode == ChangeFeedMode.AllVersionsAndDeletes)
{
Debug.WriteLine($"{nameof(properties.ChangeFeedPolicy.FullFidelityRetention)} initialized.");

properties.ChangeFeedPolicy.FullFidelityRetention = TimeSpan.FromMinutes(5);
}

Expand Down
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ Preview features are treated as a separate branch and will not be included in th
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### <a name="3.40.0-preview.1"/> [3.40.0-preview.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.40.0-preview.1) - 2024-04-17
### <a name="3.39.1"/> [3.39.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.39.1) - 2024-04-17

#### Fixed
- [4426](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/4426) ChangeFeedProcessor: Fixes ArgumentException when dealing with Legacy lease incremental documents that do not have a Mode property

### <a name="3.40.0-preview.0"/> [3.40.0-preview.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.40.0-preview.0) - 2024-04-05

#### Fixed
Expand Down

0 comments on commit 8a59688

Please sign in to comment.