mirror of
https://github.com/bitwarden/server.git
synced 2025-06-19 10:28:09 -05:00
Azure Queue Notifications Tests
This commit is contained in:
parent
1e13250292
commit
17da1c496e
@ -22,17 +22,19 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
private readonly QueueClient _queueClient;
|
private readonly QueueClient _queueClient;
|
||||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
private readonly IGlobalSettings _globalSettings;
|
private readonly IGlobalSettings _globalSettings;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public AzureQueuePushNotificationService(
|
public AzureQueuePushNotificationService(
|
||||||
[FromKeyedServices("notifications")] QueueClient queueClient,
|
[FromKeyedServices("notifications")] QueueClient queueClient,
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
IGlobalSettings globalSettings,
|
IGlobalSettings globalSettings,
|
||||||
ILogger<AzureQueuePushNotificationService> logger)
|
ILogger<AzureQueuePushNotificationService> logger,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_queueClient = queueClient;
|
_queueClient = queueClient;
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
if (globalSettings.Installation.Id == Guid.Empty)
|
if (globalSettings.Installation.Id == Guid.Empty)
|
||||||
{
|
{
|
||||||
logger.LogWarning("Installation ID is not set. Push notifications for installations will not work.");
|
logger.LogWarning("Installation ID is not set. Push notifications for installations will not work.");
|
||||||
@ -140,7 +142,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
|||||||
|
|
||||||
private async Task PushUserAsync(Guid userId, PushType type, bool excludeCurrentContext = false)
|
private async Task PushUserAsync(Guid userId, PushType type, bool excludeCurrentContext = false)
|
||||||
{
|
{
|
||||||
var message = new UserPushNotification { UserId = userId, Date = DateTime.UtcNow };
|
var message = new UserPushNotification { UserId = userId, Date = _timeProvider.GetUtcNow().UtcDateTime };
|
||||||
|
|
||||||
await SendMessageAsync(type, message, excludeCurrentContext);
|
await SendMessageAsync(type, message, excludeCurrentContext);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,27 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using Azure.Storage.Queues;
|
using Azure.Storage.Queues;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.Auth.Entities;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.NotificationCenter.Entities;
|
using Bit.Core.NotificationCenter.Entities;
|
||||||
|
using Bit.Core.NotificationCenter.Enums;
|
||||||
using Bit.Core.Platform.Push.Internal;
|
using Bit.Core.Platform.Push.Internal;
|
||||||
using Bit.Core.Settings;
|
using Bit.Core.Settings;
|
||||||
using Bit.Core.Test.AutoFixture;
|
using Bit.Core.Test.AutoFixture;
|
||||||
using Bit.Core.Test.AutoFixture.CurrentContextFixtures;
|
using Bit.Core.Test.AutoFixture.CurrentContextFixtures;
|
||||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||||
|
using Bit.Core.Tools.Entities;
|
||||||
|
using Bit.Core.Vault.Entities;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Time.Testing;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -22,6 +31,17 @@ namespace Bit.Core.Test.Platform.Push.Services;
|
|||||||
[SutProviderCustomize]
|
[SutProviderCustomize]
|
||||||
public class AzureQueuePushNotificationServiceTests
|
public class AzureQueuePushNotificationServiceTests
|
||||||
{
|
{
|
||||||
|
private static readonly Guid _deviceId = Guid.Parse("c4730f80-caaa-4772-97bd-5c0d23a2baa3");
|
||||||
|
private static readonly string _deviceIdentifier = "test_device_identifier";
|
||||||
|
private readonly FakeTimeProvider _fakeTimeProvider;
|
||||||
|
private readonly Core.Settings.GlobalSettings _globalSettings = new();
|
||||||
|
|
||||||
|
public AzureQueuePushNotificationServiceTests()
|
||||||
|
{
|
||||||
|
_fakeTimeProvider = new();
|
||||||
|
_fakeTimeProvider.SetUtcNow(DateTime.UtcNow);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
[NotificationCustomize]
|
[NotificationCustomize]
|
||||||
@ -112,6 +132,761 @@ public class AzureQueuePushNotificationServiceTests
|
|||||||
deviceIdentifier.ToString())));
|
deviceIdentifier.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("6a5bbe1b-cf16-49a6-965f-5c2eac56a531", null)]
|
||||||
|
[InlineData(null, "b9a3fcb4-2447-45c1-aad2-24de43c88c44")]
|
||||||
|
public async Task PushSyncCipherCreateAsync_SendsExpectedResponse(string? userId, string? organizationId)
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var cipher = new Cipher
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = userId != null ? Guid.Parse(userId) : null,
|
||||||
|
OrganizationId = organizationId != null ? Guid.Parse(organizationId) : null,
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 1,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = cipher.Id,
|
||||||
|
["UserId"] = cipher.UserId,
|
||||||
|
["OrganizationId"] = cipher.OrganizationId,
|
||||||
|
["CollectionIds"] = new JsonArray(collectionId),
|
||||||
|
["RevisionDate"] = cipher.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!cipher.UserId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cipher.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("OrganizationId");
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("CollectionIds");
|
||||||
|
}
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncCipherCreateAsync(cipher, [collectionId]),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("6a5bbe1b-cf16-49a6-965f-5c2eac56a531", null)]
|
||||||
|
[InlineData(null, "b9a3fcb4-2447-45c1-aad2-24de43c88c44")]
|
||||||
|
public async Task PushSyncCipherUpdateAsync_SendsExpectedResponse(string? userId, string? organizationId)
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var cipher = new Cipher
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = userId != null ? Guid.Parse(userId) : null,
|
||||||
|
OrganizationId = organizationId != null ? Guid.Parse(organizationId) : null,
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 0,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = cipher.Id,
|
||||||
|
["UserId"] = cipher.UserId,
|
||||||
|
["OrganizationId"] = cipher.OrganizationId,
|
||||||
|
["CollectionIds"] = new JsonArray(collectionId),
|
||||||
|
["RevisionDate"] = cipher.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!cipher.UserId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cipher.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("OrganizationId");
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("CollectionIds");
|
||||||
|
}
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncCipherUpdateAsync(cipher, [collectionId]),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncCipherDeleteAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var cipher = new Cipher
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
OrganizationId = null,
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 2,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = cipher.Id,
|
||||||
|
["UserId"] = cipher.UserId,
|
||||||
|
["RevisionDate"] = cipher.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncCipherDeleteAsync(cipher),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncFolderCreateAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var folder = new Folder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 7,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = folder.Id,
|
||||||
|
["UserId"] = folder.UserId,
|
||||||
|
["RevisionDate"] = folder.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncFolderCreateAsync(folder),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncFolderUpdateAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var folder = new Folder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 8,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = folder.Id,
|
||||||
|
["UserId"] = folder.UserId,
|
||||||
|
["RevisionDate"] = folder.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncFolderUpdateAsync(folder),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncFolderDeleteAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var collectionId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var folder = new Folder
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 3,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = folder.Id,
|
||||||
|
["UserId"] = folder.UserId,
|
||||||
|
["RevisionDate"] = folder.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncFolderDeleteAsync(folder),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncCiphersAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 4,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncCiphersAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncVaultAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 5,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncVaultAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncOrganizationsAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 17,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncOrganizationsAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncOrgKeysAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 6,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncOrgKeysAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncSettingsAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 10,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncSettingsAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true)]
|
||||||
|
[InlineData(false)]
|
||||||
|
public async Task PushLogOutAsync_SendsExpectedResponse(bool excludeCurrentContext)
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 11,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (excludeCurrentContext)
|
||||||
|
{
|
||||||
|
expectedPayload["ContextId"] = _deviceIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushLogOutAsync(userId, excludeCurrentContext),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncSendCreateAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var send = new Send
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 12,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = send.Id,
|
||||||
|
["UserId"] = send.UserId,
|
||||||
|
["RevisionDate"] = send.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncSendCreateAsync(send),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncSendUpdateAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var send = new Send
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 13,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = send.Id,
|
||||||
|
["UserId"] = send.UserId,
|
||||||
|
["RevisionDate"] = send.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncSendUpdateAsync(send),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncSendDeleteAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var send = new Send
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 14,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = send.Id,
|
||||||
|
["UserId"] = send.UserId,
|
||||||
|
["RevisionDate"] = send.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncSendDeleteAsync(send),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushAuthRequestAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var authRequest = new AuthRequest
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 15,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = authRequest.Id,
|
||||||
|
["UserId"] = authRequest.UserId,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushAuthRequestAsync(authRequest),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushAuthRequestResponseAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var authRequest = new AuthRequest
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 16,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = authRequest.Id,
|
||||||
|
["UserId"] = authRequest.UserId,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushAuthRequestResponseAsync(authRequest),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true, null, null)]
|
||||||
|
[InlineData(false, "e8e08ce8-8a26-4a65-913a-ba1d8c478b2f", null)]
|
||||||
|
[InlineData(false, null, "2f53ee32-edf9-4169-b276-760fe92e03bf")]
|
||||||
|
public async Task PushNotificationAsync_SendsExpectedResponse(bool global, string? userId, string? organizationId)
|
||||||
|
{
|
||||||
|
var notification = new Notification
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Priority = Priority.High,
|
||||||
|
Global = global,
|
||||||
|
ClientType = ClientType.All,
|
||||||
|
UserId = userId != null ? Guid.Parse(userId) : null,
|
||||||
|
OrganizationId = organizationId != null ? Guid.Parse(organizationId) : null,
|
||||||
|
Title = "My Title",
|
||||||
|
Body = "My Body",
|
||||||
|
CreationDate = DateTime.UtcNow.AddDays(-1),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 20,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = notification.Id,
|
||||||
|
["Priority"] = 3,
|
||||||
|
["Global"] = global,
|
||||||
|
["ClientType"] = 0,
|
||||||
|
["UserId"] = notification.UserId,
|
||||||
|
["OrganizationId"] = notification.OrganizationId,
|
||||||
|
["InstallationId"] = _globalSettings.Installation.Id,
|
||||||
|
["Title"] = notification.Title,
|
||||||
|
["Body"] = notification.Body,
|
||||||
|
["CreationDate"] = notification.CreationDate,
|
||||||
|
["RevisionDate"] = notification.RevisionDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!global)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("InstallationId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notification.UserId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notification.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("OrganizationId");
|
||||||
|
}
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushNotificationAsync(notification),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true, null, null)]
|
||||||
|
[InlineData(false, "e8e08ce8-8a26-4a65-913a-ba1d8c478b2f", null)]
|
||||||
|
[InlineData(false, null, "2f53ee32-edf9-4169-b276-760fe92e03bf")]
|
||||||
|
public async Task PushNotificationStatusAsync_SendsExpectedResponse(bool global, string? userId, string? organizationId)
|
||||||
|
{
|
||||||
|
var notification = new Notification
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Priority = Priority.High,
|
||||||
|
Global = global,
|
||||||
|
ClientType = ClientType.All,
|
||||||
|
UserId = userId != null ? Guid.Parse(userId) : null,
|
||||||
|
OrganizationId = organizationId != null ? Guid.Parse(organizationId) : null,
|
||||||
|
Title = "My Title",
|
||||||
|
Body = "My Body",
|
||||||
|
CreationDate = DateTime.UtcNow.AddDays(-1),
|
||||||
|
RevisionDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var notificationStatus = new NotificationStatus
|
||||||
|
{
|
||||||
|
ReadDate = DateTime.UtcNow,
|
||||||
|
DeletedDate = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 21,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["Id"] = notification.Id,
|
||||||
|
["Priority"] = 3,
|
||||||
|
["Global"] = global,
|
||||||
|
["ClientType"] = 0,
|
||||||
|
["UserId"] = notification.UserId,
|
||||||
|
["OrganizationId"] = notification.OrganizationId,
|
||||||
|
["InstallationId"] = _globalSettings.Installation.Id,
|
||||||
|
["Title"] = notification.Title,
|
||||||
|
["Body"] = notification.Body,
|
||||||
|
["CreationDate"] = notification.CreationDate,
|
||||||
|
["RevisionDate"] = notification.RevisionDate,
|
||||||
|
["ReadDate"] = notificationStatus.ReadDate,
|
||||||
|
["DeletedDate"] = notificationStatus.DeletedDate,
|
||||||
|
},
|
||||||
|
["ContextId"] = _deviceIdentifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!global)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("InstallationId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notification.UserId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notification.OrganizationId.HasValue)
|
||||||
|
{
|
||||||
|
expectedPayload["Payload"]!.AsObject().Remove("OrganizationId");
|
||||||
|
}
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushNotificationStatusAsync(notification, notificationStatus),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncOrganizationStatusAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var organization = new Organization
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Enabled = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 18,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["OrganizationId"] = organization.Id,
|
||||||
|
["Enabled"] = organization.Enabled,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncOrganizationStatusAsync(organization),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushSyncOrganizationCollectionManagementSettingsAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var organization = new Organization
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Enabled = true,
|
||||||
|
LimitCollectionCreation = true,
|
||||||
|
LimitCollectionDeletion = true,
|
||||||
|
LimitItemDeletion = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 19,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["OrganizationId"] = organization.Id,
|
||||||
|
["LimitCollectionCreation"] = organization.LimitCollectionCreation,
|
||||||
|
["LimitCollectionDeletion"] = organization.LimitCollectionDeletion,
|
||||||
|
["LimitItemDeletion"] = organization.LimitItemDeletion,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushSyncOrganizationCollectionManagementSettingsAsync(organization),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PushPendingSecurityTasksAsync_SendsExpectedResponse()
|
||||||
|
{
|
||||||
|
var userId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var expectedPayload = new JsonObject
|
||||||
|
{
|
||||||
|
["Type"] = 22,
|
||||||
|
["Payload"] = new JsonObject
|
||||||
|
{
|
||||||
|
["UserId"] = userId,
|
||||||
|
["Date"] = _fakeTimeProvider.GetUtcNow().UtcDateTime,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await VerifyNotificationAsync(
|
||||||
|
async sut => await sut.PushPendingSecurityTasksAsync(userId),
|
||||||
|
expectedPayload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Fact]
|
||||||
|
// public async Task SendPayloadToInstallationAsync_ThrowsNotImplementedException()
|
||||||
|
// {
|
||||||
|
// await Assert.ThrowsAsync<NotImplementedException>(
|
||||||
|
// async () => await sut.SendPayloadToInstallationAsync("installation_id", PushType.AuthRequest, new {}, null)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// [Fact]
|
||||||
|
// public async Task SendPayloadToUserAsync_ThrowsNotImplementedException()
|
||||||
|
// {
|
||||||
|
// await Assert.ThrowsAsync<NotImplementedException>(
|
||||||
|
// async () => await _sut.SendPayloadToUserAsync("user_id", PushType.AuthRequest, new {}, null)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// [Fact]
|
||||||
|
// public async Task SendPayloadToOrganizationAsync_ThrowsNotImplementedException()
|
||||||
|
// {
|
||||||
|
// await Assert.ThrowsAsync<NotImplementedException>(
|
||||||
|
// async () => await _sut.SendPayloadToOrganizationAsync("organization_id", PushType.AuthRequest, new {}, null)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
private async Task VerifyNotificationAsync(Func<AzureQueuePushNotificationService, Task> test, JsonNode expectedMessage)
|
||||||
|
{
|
||||||
|
var queueClient = Substitute.For<QueueClient>();
|
||||||
|
|
||||||
|
var httpContextAccessor = Substitute.For<IHttpContextAccessor>();
|
||||||
|
|
||||||
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
var serviceCollection = new ServiceCollection();
|
||||||
|
var currentContext = Substitute.For<ICurrentContext>();
|
||||||
|
currentContext.DeviceIdentifier = _deviceIdentifier;
|
||||||
|
serviceCollection.AddSingleton(currentContext);
|
||||||
|
|
||||||
|
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
httpContextAccessor.HttpContext
|
||||||
|
.Returns(httpContext);
|
||||||
|
|
||||||
|
var globalSettings = new Core.Settings.GlobalSettings();
|
||||||
|
|
||||||
|
var sut = new AzureQueuePushNotificationService(
|
||||||
|
queueClient,
|
||||||
|
httpContextAccessor,
|
||||||
|
globalSettings,
|
||||||
|
NullLogger<AzureQueuePushNotificationService>.Instance,
|
||||||
|
_fakeTimeProvider
|
||||||
|
);
|
||||||
|
|
||||||
|
await test(sut);
|
||||||
|
|
||||||
|
// Hoist equality checker outside the expression so that we
|
||||||
|
// can more easily place a breakpoint
|
||||||
|
var checkEquality = (string actual) =>
|
||||||
|
{
|
||||||
|
var actualNode = JsonNode.Parse(actual);
|
||||||
|
return JsonNode.DeepEquals(actualNode, expectedMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
await queueClient
|
||||||
|
.Received(1)
|
||||||
|
.SendMessageAsync(Arg.Is<string>((actual) => checkEquality(actual)));
|
||||||
|
}
|
||||||
|
|
||||||
private static bool MatchMessage<T>(PushType pushType, string message, IEquatable<T> expectedPayloadEquatable,
|
private static bool MatchMessage<T>(PushType pushType, string message, IEquatable<T> expectedPayloadEquatable,
|
||||||
string contextId)
|
string contextId)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user