Fixing double root folder creation.

This commit is contained in:
Burak Kaan Köse
2026-04-16 14:06:14 +02:00
parent e1f53c7f9f
commit 0b136b3d66
2 changed files with 111 additions and 3 deletions
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using FluentAssertions;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.MailItem;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.Requests.Folder;
using Wino.Core.Synchronizers;
using Xunit;
namespace Wino.Core.Tests.Synchronizers;
public sealed class WinoSynchronizerMailRequestTests
{
[Fact]
public async Task FoldersOnly_sync_should_not_execute_queued_folder_requests()
{
var synchronizer = new TestMailSynchronizer();
var request = new CreateRootFolderRequest(
new MailItemFolder { Id = Guid.NewGuid(), MailAccountId = synchronizer.Account.Id },
"test");
synchronizer.QueueRequest(request);
var foldersOnlyResult = await synchronizer.SynchronizeMailsAsync(new MailSynchronizationOptions
{
AccountId = synchronizer.Account.Id,
Type = MailSynchronizationType.FoldersOnly
});
foldersOnlyResult.CompletedState.Should().Be(SynchronizationCompletedState.Success);
synchronizer.CreateRootFolderInvocationCount.Should().Be(0);
synchronizer.ExecuteNativeRequestsInvocationCount.Should().Be(0);
var executeRequestsResult = await synchronizer.SynchronizeMailsAsync(new MailSynchronizationOptions
{
AccountId = synchronizer.Account.Id,
Type = MailSynchronizationType.ExecuteRequests
});
executeRequestsResult.CompletedState.Should().Be(SynchronizationCompletedState.Success);
synchronizer.CreateRootFolderInvocationCount.Should().Be(1);
synchronizer.ExecuteNativeRequestsInvocationCount.Should().Be(1);
}
private sealed class TestMailSynchronizer
: WinoSynchronizer<object, object, object>
{
public TestMailSynchronizer()
: base(new MailAccount { Id = Guid.NewGuid(), Name = "Test account" }, WeakReferenceMessenger.Default)
{
}
public override uint BatchModificationSize => 1;
public override uint InitialMessageDownloadCountPerFolder => 0;
public int CreateRootFolderInvocationCount { get; private set; }
public int ExecuteNativeRequestsInvocationCount { get; private set; }
public override List<IRequestBundle<object>> CreateRootFolder(CreateRootFolderRequest request)
{
CreateRootFolderInvocationCount++;
return [new TestRequestBundle(new object(), request)];
}
public override Task ExecuteNativeRequestsAsync(List<IRequestBundle<object>> batchedRequests, CancellationToken cancellationToken = default)
{
ExecuteNativeRequestsInvocationCount++;
return Task.CompletedTask;
}
public override Task<List<NewMailItemPackage>> CreateNewMailPackagesAsync(
object message,
MailItemFolder assignedFolder,
CancellationToken cancellationToken = default)
=> Task.FromResult(new List<NewMailItemPackage>());
protected override Task<MailSynchronizationResult> SynchronizeMailsInternalAsync(
MailSynchronizationOptions options,
CancellationToken cancellationToken = default)
=> Task.FromResult(MailSynchronizationResult.Empty);
protected override Task<CalendarSynchronizationResult> SynchronizeCalendarEventsInternalAsync(
CalendarSynchronizationOptions options,
CancellationToken cancellationToken = default)
=> Task.FromResult(CalendarSynchronizationResult.Empty);
}
private sealed class TestRequestBundle : IRequestBundle<object>
{
public TestRequestBundle(object nativeRequest, IRequestBase request)
{
NativeRequest = nativeRequest;
Request = request;
}
public string BundleId { get; set; } = Guid.NewGuid().ToString();
public IUIChangeRequest UIChangeRequest => Request;
public object NativeRequest { get; }
public IRequestBase Request { get; }
}
}
+4 -3
View File
@@ -140,9 +140,10 @@ public abstract class WinoSynchronizer<TBaseRequest, TMessageType, TCalendarEven
PendingSynchronizationRequest.Add(options, newCancellationTokenSource); PendingSynchronizationRequest.Add(options, newCancellationTokenSource);
activeSynchronizationCancellationToken = newCancellationTokenSource.Token; activeSynchronizationCancellationToken = newCancellationTokenSource.Token;
// ImapSynchronizer will send this type when an Idle client receives a notification of changes. // Only explicit ExecuteRequests runs are allowed to drain the queued request list.
// We should not execute requests in this case. // Other sync types (for example the follow-up FoldersOnly refresh after folder actions)
bool shouldExecuteRequests = options.Type != MailSynchronizationType.IMAPIdle; // may be queued alongside ExecuteRequests and must not replay the same operations.
bool shouldExecuteRequests = options.Type == MailSynchronizationType.ExecuteRequests;
bool shouldDelayExecution = false; bool shouldDelayExecution = false;
int maxExecutionDelay = 0; int maxExecutionDelay = 0;