Change Feed / Processor AVAD: Fixes timeToLiveExpired missing from metadata (#4523)

* longrunning cfp avad test for ttl

* add more to comment

* internal set

* other tests fail with higher ms

* run updatecontracts

* Update Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

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

* Update Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

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

* Update Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

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

* Update Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

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

* using Logger.LogLine

* change back over to ManualResetEvent. fixed assert to look at Previous. keeping stopwatch just for logging. timeout at 5 minutes.

* Update GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

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

* try/finally

* removing ctor. making all set internal to address serialization issue. later PRs to test STJ de/serialization.

* fixing de/serialziation issue

* Update GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.cs

change timeout

* Update ReEncryption.csproj

1.11.4

* internal set change to CanWrite:True;

---------

Co-authored-by: Matias Quaranta <ealsur@users.noreply.github.com>
This commit is contained in:
Philip Thomas 2024-06-19 12:02:47 -04:00 коммит произвёл GitHub
Родитель c5ac103a63
Коммит aab02e502e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 125 добавлений и 31 удалений

Просмотреть файл

@ -19,55 +19,36 @@ namespace Microsoft.Azure.Cosmos
#endif
class ChangeFeedMetadata
{
/// <summary>
/// New instance of meta data for <see cref="ChangeFeedItem{T}"/> created.
/// </summary>
/// <param name="conflictResolutionTimestamp"></param>
/// <param name="lsn"></param>
/// <param name="operationType"></param>
/// <param name="previousLsn"></param>
public ChangeFeedMetadata(
DateTime conflictResolutionTimestamp,
long lsn,
ChangeFeedOperationType operationType,
long previousLsn)
{
this.ConflictResolutionTimestamp = conflictResolutionTimestamp;
this.Lsn = lsn;
this.OperationType = operationType;
this.PreviousLsn = previousLsn;
}
/// <summary>
/// The conflict resolution timestamp.
/// </summary>
[JsonProperty(PropertyName = "crts", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(UnixDateTimeConverter))]
public DateTime ConflictResolutionTimestamp { get; }
public DateTime ConflictResolutionTimestamp { get; internal set; }
/// <summary>
/// The current logical sequence number.
/// </summary>
[JsonProperty(PropertyName = "lsn", NullValueHandling = NullValueHandling.Ignore)]
public long Lsn { get; }
public long Lsn { get; internal set; }
/// <summary>
/// The change feed operation type.
/// </summary>
[JsonProperty(PropertyName = "operationType")]
[JsonConverter(typeof(StringEnumConverter))]
public ChangeFeedOperationType OperationType { get; }
public ChangeFeedOperationType OperationType { get; internal set; }
/// <summary>
/// The previous logical sequence number.
/// </summary>
[JsonProperty(PropertyName = "previousImageLSN", NullValueHandling = NullValueHandling.Ignore)]
public long PreviousLsn { get; }
public long PreviousLsn { get; internal set; }
/// <summary>
/// Used to distinquish explicit deletes (e.g. via DeleteItem) from deletes caused by TTL expiration (a collection may define time-to-live policy for documents).
/// </summary>
[JsonProperty(PropertyName = "timeToLiveExpired", NullValueHandling= NullValueHandling.Ignore)]
public bool IsTimeToLiveExpired { get; }
public bool IsTimeToLiveExpired { get; internal set; }
}
}

Просмотреть файл

@ -6,11 +6,14 @@ 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.Azure.Cosmos.Services.Management.Tests;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
[TestClass]
@ -29,6 +32,115 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests.ChangeFeed
await base.TestCleanup();
}
[TestMethod]
[Timeout(300000)]
[TestCategory("LongRunning")]
[Owner("philipthomas-MSFT")]
[Description("Scenario: When a document is created with ttl set, there should be 1 create and 1 delete that will appear for that " +
"document when using ChangeFeedProcessor with AllVersionsAndDeletes set as the ChangeFeedMode.")]
public async Task WhenADocumentIsCreatedWithTtlSetThenTheDocumentIsDeletedTestsAsync()
{
ContainerInternal monitoredContainer = await this.CreateMonitoredContainer(ChangeFeedMode.AllVersionsAndDeletes);
Exception exception = default;
int ttlInSeconds = 5;
Stopwatch stopwatch = new();
ManualResetEvent allDocsProcessed = new ManualResetEvent(false);
ChangeFeedProcessor processor = monitoredContainer
.GetChangeFeedProcessorBuilderWithAllVersionsAndDeletes(processorName: "processor", onChangesDelegate: (ChangeFeedProcessorContext context, IReadOnlyCollection<ChangeFeedItem<dynamic>> docs, CancellationToken token) =>
{
// NOTE(philipthomas-MSFT): Please allow these Logger.LogLine because TTL on items will purge at random times so I am using this to test when ran locally using emulator.
Logger.LogLine($"@ {DateTime.Now}, {nameof(stopwatch)} -> CFP AVAD took '{stopwatch.ElapsedMilliseconds}' to read document CRUD in feed.");
Logger.LogLine($"@ {DateTime.Now}, {nameof(docs)} -> {JsonConvert.SerializeObject(docs)}");
foreach (ChangeFeedItem<dynamic> change in docs)
{
if (change.Metadata.OperationType == ChangeFeedOperationType.Create)
{
// current
Assert.AreEqual(expected: "1", actual: change.Current.id.ToString());
Assert.AreEqual(expected: "1", actual: change.Current.pk.ToString());
Assert.AreEqual(expected: "Testing TTL on CFP.", actual: change.Current.description.ToString());
Assert.AreEqual(expected: ttlInSeconds, actual: change.Current.ttl.ToObject<int>());
// metadata
Assert.IsTrue(DateTime.TryParse(s: change.Metadata.ConflictResolutionTimestamp.ToString(), out _), message: "Invalid csrt must be a datetime value.");
Assert.IsTrue(change.Metadata.Lsn > 0, message: "Invalid lsn must be a long value.");
Assert.IsFalse(change.Metadata.IsTimeToLiveExpired);
// previous
Assert.IsNull(change.Previous);
}
else if (change.Metadata.OperationType == ChangeFeedOperationType.Delete)
{
// current
Assert.IsNull(change.Current.id);
// metadata
Assert.IsTrue(DateTime.TryParse(s: change.Metadata.ConflictResolutionTimestamp.ToString(), out _), message: "Invalid csrt must be a datetime value.");
Assert.IsTrue(change.Metadata.Lsn > 0, message: "Invalid lsn must be a long value.");
Assert.IsTrue(change.Metadata.IsTimeToLiveExpired);
// previous
Assert.AreEqual(expected: "1", actual: change.Previous.id.ToString());
Assert.AreEqual(expected: "1", actual: change.Previous.pk.ToString());
Assert.AreEqual(expected: "Testing TTL on CFP.", actual: change.Previous.description.ToString());
Assert.AreEqual(expected: ttlInSeconds, actual: change.Previous.ttl.ToObject<int>());
// stop after reading delete since it is the last document in feed.
stopwatch.Stop();
allDocsProcessed.Set();
}
else
{
Assert.Fail("Invalid operation.");
}
}
return Task.CompletedTask;
})
.WithInstanceName(Guid.NewGuid().ToString())
.WithLeaseContainer(this.LeaseContainer)
.WithErrorNotification((leaseToken, error) =>
{
exception = error.InnerException;
return Task.CompletedTask;
})
.Build();
stopwatch.Start();
// NOTE(philipthomas-MSFT): Please allow these Logger.LogLine because TTL on items will purge at random times so I am using this to test when ran locally using emulator.
Logger.LogLine($"@ {DateTime.Now}, CFProcessor starting...");
await processor.StartAsync();
try
{
await Task.Delay(GetChangeFeedProcessorBuilderWithAllVersionsAndDeletesTests.ChangeFeedSetupTime);
await monitoredContainer.CreateItemAsync<dynamic>(new { id = "1", pk = "1", description = "Testing TTL on CFP.", ttl = ttlInSeconds }, partitionKey: new PartitionKey("1"));
// NOTE(philipthomas-MSFT): Please allow these Logger.LogLine because TTL on items will purge at random times so I am using this to test when ran locally using emulator.
Logger.LogLine($"@ {DateTime.Now}, Document created.");
bool receivedDelete = allDocsProcessed.WaitOne(250000);
Assert.IsTrue(receivedDelete, "Timed out waiting for docs to process");
if (exception != default)
{
Assert.Fail(exception.ToString());
}
}
finally
{
await processor.StopAsync();
}
}
[TestMethod]
[Owner("philipthomas-MSFT")]
[Description("Scenario: When a document is created, then updated, and finally deleted, there should be 3 changes that will appear for that " +
@ -467,6 +579,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests.ChangeFeed
if (changeFeedMode == ChangeFeedMode.AllVersionsAndDeletes)
{
properties.ChangeFeedPolicy.FullFidelityRetention = TimeSpan.FromMinutes(5);
properties.DefaultTimeToLive = -1;
}
ContainerResponse response = await this.database.CreateContainerAsync(properties,

Просмотреть файл

@ -89,7 +89,7 @@
"Attributes": [
"JsonPropertyAttribute"
],
"MethodInfo": "Boolean IsTimeToLiveExpired;CanRead:True;CanWrite:False;Boolean get_IsTimeToLiveExpired();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
"MethodInfo": "Boolean IsTimeToLiveExpired;CanRead:True;CanWrite:True;Boolean get_IsTimeToLiveExpired();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Int64 get_Lsn()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
@ -110,14 +110,14 @@
"Attributes": [
"JsonPropertyAttribute"
],
"MethodInfo": "Int64 Lsn;CanRead:True;CanWrite:False;Int64 get_Lsn();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
"MethodInfo": "Int64 Lsn;CanRead:True;CanWrite:True;Int64 get_Lsn();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Int64 PreviousLsn[Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = 1, PropertyName = \"previousImageLSN\")]": {
"Type": "Property",
"Attributes": [
"JsonPropertyAttribute"
],
"MethodInfo": "Int64 PreviousLsn;CanRead:True;CanWrite:False;Int64 get_PreviousLsn();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
"MethodInfo": "Int64 PreviousLsn;CanRead:True;CanWrite:True;Int64 get_PreviousLsn();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Microsoft.Azure.Cosmos.ChangeFeedOperationType get_OperationType()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
@ -132,7 +132,7 @@
"JsonConverterAttribute",
"JsonPropertyAttribute"
],
"MethodInfo": "Microsoft.Azure.Cosmos.ChangeFeedOperationType OperationType;CanRead:True;CanWrite:False;Microsoft.Azure.Cosmos.ChangeFeedOperationType get_OperationType();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
"MethodInfo": "Microsoft.Azure.Cosmos.ChangeFeedOperationType OperationType;CanRead:True;CanWrite:True;Microsoft.Azure.Cosmos.ChangeFeedOperationType get_OperationType();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.DateTime ConflictResolutionTimestamp[Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = 1, PropertyName = \"crts\")]-[Newtonsoft.Json.JsonConverterAttribute(typeof(Microsoft.Azure.Documents.UnixDateTimeConverter))]": {
"Type": "Property",
@ -140,7 +140,7 @@
"JsonConverterAttribute",
"JsonPropertyAttribute"
],
"MethodInfo": "System.DateTime ConflictResolutionTimestamp;CanRead:True;CanWrite:False;System.DateTime get_ConflictResolutionTimestamp();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
"MethodInfo": "System.DateTime ConflictResolutionTimestamp;CanRead:True;CanWrite:True;System.DateTime get_ConflictResolutionTimestamp();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"System.DateTime get_ConflictResolutionTimestamp()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
"Type": "Method",
@ -149,10 +149,10 @@
],
"MethodInfo": "System.DateTime get_ConflictResolutionTimestamp();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;"
},
"Void .ctor(System.DateTime, Int64, Microsoft.Azure.Cosmos.ChangeFeedOperationType, Int64)": {
"Void .ctor()": {
"Type": "Constructor",
"Attributes": [],
"MethodInfo": "[Void .ctor(System.DateTime, Int64, Microsoft.Azure.Cosmos.ChangeFeedOperationType, Int64), Void .ctor(System.DateTime, Int64, Microsoft.Azure.Cosmos.ChangeFeedOperationType, Int64)]"
"MethodInfo": "[Void .ctor(), Void .ctor()]"
}
},
"NestedTypes": {}