WebPush-and-photo-upload-fixes
This commit is contained in:
353
LittleShop.Tests/Unit/PushNotificationControllerTests.cs
Normal file
353
LittleShop.Tests/Unit/PushNotificationControllerTests.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LittleShop.Controllers;
|
||||
using LittleShop.Services;
|
||||
using LittleShop.DTOs;
|
||||
|
||||
namespace LittleShop.Tests.Unit;
|
||||
|
||||
public class PushNotificationControllerTests
|
||||
{
|
||||
private readonly Mock<IPushNotificationService> _pushServiceMock;
|
||||
private readonly PushNotificationController _controller;
|
||||
private readonly Guid _testUserId = Guid.NewGuid();
|
||||
|
||||
public PushNotificationControllerTests()
|
||||
{
|
||||
_pushServiceMock = new Mock<IPushNotificationService>();
|
||||
_controller = new PushNotificationController(_pushServiceMock.Object);
|
||||
|
||||
// Setup controller context for authenticated user
|
||||
SetupControllerContext();
|
||||
}
|
||||
|
||||
private void SetupControllerContext()
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, _testUserId.ToString()),
|
||||
new Claim(ClaimTypes.Role, "Admin")
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuth");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext
|
||||
{
|
||||
User = principal,
|
||||
Connection = { RemoteIpAddress = System.Net.IPAddress.Parse("192.168.1.1") }
|
||||
}
|
||||
};
|
||||
|
||||
// Setup User-Agent header
|
||||
_controller.HttpContext.Request.Headers.Add("User-Agent", "TestBrowser/1.0");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVapidPublicKey_ReturnsPublicKey()
|
||||
{
|
||||
// Arrange
|
||||
var expectedKey = "test-public-key";
|
||||
_pushServiceMock.Setup(s => s.GetVapidPublicKey()).Returns(expectedKey);
|
||||
|
||||
// Act
|
||||
var result = _controller.GetVapidPublicKey();
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal(expectedKey, value.publicKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVapidPublicKey_ReturnsInternalServerError_OnException()
|
||||
{
|
||||
// Arrange
|
||||
_pushServiceMock.Setup(s => s.GetVapidPublicKey()).Throws(new Exception("Test exception"));
|
||||
|
||||
// Act
|
||||
var result = _controller.GetVapidPublicKey();
|
||||
|
||||
// Assert
|
||||
var statusResult = Assert.IsType<ObjectResult>(result);
|
||||
Assert.Equal(500, statusResult.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Subscribe_ReturnsOk_WhenSubscriptionSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SubscribeUserAsync(_testUserId, subscriptionDto, "TestBrowser/1.0", "192.168.1.1"))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
// Act
|
||||
var result = await _controller.Subscribe(subscriptionDto);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Successfully subscribed to push notifications", value.message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Subscribe_ReturnsInternalServerError_WhenSubscriptionFails()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SubscribeUserAsync(It.IsAny<Guid>(), It.IsAny<PushSubscriptionDto>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
// Act
|
||||
var result = await _controller.Subscribe(subscriptionDto);
|
||||
|
||||
// Assert
|
||||
var statusResult = Assert.IsType<ObjectResult>(result);
|
||||
Assert.Equal(500, statusResult.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Subscribe_ReturnsUnauthorized_WhenUserIdInvalid()
|
||||
{
|
||||
// Arrange
|
||||
// Setup controller with invalid user ID
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, "invalid-guid"),
|
||||
new Claim(ClaimTypes.Role, "Admin")
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuth");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
_controller.ControllerContext.HttpContext.User = principal;
|
||||
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.Subscribe(subscriptionDto);
|
||||
|
||||
// Assert
|
||||
var unauthorizedResult = Assert.IsType<UnauthorizedObjectResult>(result);
|
||||
dynamic value = unauthorizedResult.Value;
|
||||
Assert.Equal("Invalid user ID", value.error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SubscribeCustomer_ReturnsOk_WhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var customerId = Guid.NewGuid();
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/customer",
|
||||
P256DH = "customer-p256dh",
|
||||
Auth = "customer-auth"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SubscribeCustomerAsync(customerId, subscriptionDto, It.IsAny<string>(), It.IsAny<string>()))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
// Act
|
||||
var result = await _controller.SubscribeCustomer(subscriptionDto, customerId);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Successfully subscribed to push notifications", value.message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SubscribeCustomer_ReturnsBadRequest_WhenCustomerIdEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/customer",
|
||||
P256DH = "customer-p256dh",
|
||||
Auth = "customer-auth"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.SubscribeCustomer(subscriptionDto, Guid.Empty);
|
||||
|
||||
// Assert
|
||||
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
|
||||
dynamic value = badRequestResult.Value;
|
||||
Assert.Equal("Invalid customer ID", value.error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Unsubscribe_ReturnsOk_WhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var unsubscribeDto = new UnsubscribeDto { Endpoint = "https://fcm.googleapis.com/fcm/send/test" };
|
||||
_pushServiceMock.Setup(s => s.UnsubscribeAsync(unsubscribeDto.Endpoint)).ReturnsAsync(true);
|
||||
|
||||
// Act
|
||||
var result = await _controller.Unsubscribe(unsubscribeDto);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Successfully unsubscribed from push notifications", value.message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Unsubscribe_ReturnsNotFound_WhenSubscriptionNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var unsubscribeDto = new UnsubscribeDto { Endpoint = "https://fcm.googleapis.com/fcm/send/nonexistent" };
|
||||
_pushServiceMock.Setup(s => s.UnsubscribeAsync(unsubscribeDto.Endpoint)).ReturnsAsync(false);
|
||||
|
||||
// Act
|
||||
var result = await _controller.Unsubscribe(unsubscribeDto);
|
||||
|
||||
// Assert
|
||||
var notFoundResult = Assert.IsType<NotFoundObjectResult>(result);
|
||||
dynamic value = notFoundResult.Value;
|
||||
Assert.Equal("Subscription not found", value.error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendTestNotification_ReturnsOk_WhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var testDto = new TestPushNotificationDto
|
||||
{
|
||||
Title = "Test Title",
|
||||
Body = "Test Body"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SendTestNotificationAsync(_testUserId.ToString(), testDto.Title, testDto.Body))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
// Act
|
||||
var result = await _controller.SendTestNotification(testDto);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Test notification sent successfully", value.message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendTestNotification_ReturnsInternalServerError_WhenFails()
|
||||
{
|
||||
// Arrange
|
||||
var testDto = new TestPushNotificationDto
|
||||
{
|
||||
Title = "Test Title",
|
||||
Body = "Test Body"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SendTestNotificationAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
// Act
|
||||
var result = await _controller.SendTestNotification(testDto);
|
||||
|
||||
// Assert
|
||||
var statusResult = Assert.IsType<ObjectResult>(result);
|
||||
Assert.Equal(500, statusResult.StatusCode);
|
||||
dynamic value = statusResult.Value;
|
||||
Assert.Contains("Failed to send test notification", (string)value.error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendBroadcastNotification_ReturnsOk_WhenSuccessful()
|
||||
{
|
||||
// Arrange
|
||||
var notificationDto = new PushNotificationDto
|
||||
{
|
||||
Title = "Broadcast Title",
|
||||
Body = "Broadcast Body"
|
||||
};
|
||||
|
||||
_pushServiceMock
|
||||
.Setup(s => s.SendNotificationToAllUsersAsync(notificationDto))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
// Act
|
||||
var result = await _controller.SendBroadcastNotification(notificationDto);
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Broadcast notification sent successfully", value.message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetActiveSubscriptions_ReturnsOk_WithSubscriptions()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptions = new List<LittleShop.Models.PushSubscription>
|
||||
{
|
||||
new LittleShop.Models.PushSubscription
|
||||
{
|
||||
Id = 1,
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test-long-endpoint-that-should-be-truncated",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
LastUsedAt = DateTime.UtcNow,
|
||||
UserAgent = "TestBrowser/1.0",
|
||||
User = new LittleShop.Models.User { Username = "testuser" }
|
||||
}
|
||||
};
|
||||
|
||||
_pushServiceMock.Setup(s => s.GetActiveSubscriptionsAsync()).ReturnsAsync(subscriptions);
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetActiveSubscriptions();
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
var subscriptionList = okResult.Value as IEnumerable<dynamic>;
|
||||
Assert.NotNull(subscriptionList);
|
||||
Assert.Single(subscriptionList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CleanupExpiredSubscriptions_ReturnsOk_WithCleanupCount()
|
||||
{
|
||||
// Arrange
|
||||
_pushServiceMock.Setup(s => s.CleanupExpiredSubscriptionsAsync()).ReturnsAsync(5);
|
||||
|
||||
// Act
|
||||
var result = await _controller.CleanupExpiredSubscriptions();
|
||||
|
||||
// Assert
|
||||
var okResult = Assert.IsType<OkObjectResult>(result);
|
||||
dynamic value = okResult.Value;
|
||||
Assert.Equal("Cleaned up 5 expired subscriptions", value.message);
|
||||
}
|
||||
}
|
||||
358
LittleShop.Tests/Unit/PushNotificationServiceTests.cs
Normal file
358
LittleShop.Tests/Unit/PushNotificationServiceTests.cs
Normal file
@@ -0,0 +1,358 @@
|
||||
using Xunit;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
using LittleShop.Services;
|
||||
using LittleShop.Data;
|
||||
using LittleShop.Models;
|
||||
using LittleShop.DTOs;
|
||||
using WebPush;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LittleShop.Tests.Unit;
|
||||
|
||||
public class PushNotificationServiceTests : IDisposable
|
||||
{
|
||||
private readonly LittleShopContext _context;
|
||||
private readonly Mock<IConfiguration> _configurationMock;
|
||||
private readonly PushNotificationService _service;
|
||||
private readonly Guid _testUserId = Guid.NewGuid();
|
||||
private readonly Guid _testCustomerId = Guid.NewGuid();
|
||||
|
||||
public PushNotificationServiceTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<LittleShopContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new LittleShopContext(options);
|
||||
|
||||
// Setup configuration mock with VAPID keys
|
||||
_configurationMock = new Mock<IConfiguration>();
|
||||
_configurationMock.Setup(c => c["WebPush:VapidPublicKey"])
|
||||
.Returns("BMc6fFJZ8oIQKQzcl3kMnP9tTsjrm3oI_VxLt3lAGYUMWGInzDKn7jqclEoZzjvXy1QXGFb3dIun8mVBwh-QuS4");
|
||||
_configurationMock.Setup(c => c["WebPush:VapidPrivateKey"])
|
||||
.Returns("dYuuagbz2CzCnPDFUpO_qkGLBgnN3MEFZQnjXNkc1MY");
|
||||
_configurationMock.Setup(c => c["WebPush:Subject"])
|
||||
.Returns("mailto:admin@littleshop.local");
|
||||
|
||||
_service = new PushNotificationService(_context, _configurationMock.Object);
|
||||
|
||||
// Seed test data
|
||||
SeedTestData();
|
||||
}
|
||||
|
||||
private void SeedTestData()
|
||||
{
|
||||
var testUser = new User
|
||||
{
|
||||
Id = _testUserId,
|
||||
Username = "testuser",
|
||||
PasswordHash = "hash",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
var testCustomer = new Customer
|
||||
{
|
||||
Id = _testCustomerId,
|
||||
TelegramUserId = 123456,
|
||||
TelegramUsername = "testcustomer",
|
||||
TelegramDisplayName = "Test Customer",
|
||||
TelegramFirstName = "Test",
|
||||
TelegramLastName = "Customer",
|
||||
Language = "en",
|
||||
Timezone = "UTC",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
LastActiveAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
_context.Users.Add(testUser);
|
||||
_context.Customers.Add(testCustomer);
|
||||
_context.SaveChanges();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetVapidPublicKey_ReturnsCorrectKey()
|
||||
{
|
||||
// Act
|
||||
var result = _service.GetVapidPublicKey();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("BMc6fFJZ8oIQKQzcl3kMnP9tTsjrm3oI_VxLt3lAGYUMWGInzDKn7jqclEoZzjvXy1QXGFb3dIun8mVBwh-QuS4", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SubscribeUserAsync_CreatesNewSubscription_WhenNotExists()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _service.SubscribeUserAsync(_testUserId, subscriptionDto, "test-agent", "192.168.1.1");
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
var subscription = await _context.PushSubscriptions.FirstOrDefaultAsync();
|
||||
Assert.NotNull(subscription);
|
||||
Assert.Equal(_testUserId, subscription.UserId);
|
||||
Assert.Equal(subscriptionDto.Endpoint, subscription.Endpoint);
|
||||
Assert.Equal(subscriptionDto.P256DH, subscription.P256DH);
|
||||
Assert.Equal(subscriptionDto.Auth, subscription.Auth);
|
||||
Assert.Equal("test-agent", subscription.UserAgent);
|
||||
Assert.Equal("192.168.1.1", subscription.IpAddress);
|
||||
Assert.True(subscription.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SubscribeUserAsync_UpdatesExistingSubscription_WhenExists()
|
||||
{
|
||||
// Arrange
|
||||
var existingSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "old-p256dh",
|
||||
Auth = "old-auth",
|
||||
SubscribedAt = DateTime.UtcNow.AddDays(-1),
|
||||
IsActive = false
|
||||
};
|
||||
_context.PushSubscriptions.Add(existingSubscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "new-p256dh",
|
||||
Auth = "new-auth"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _service.SubscribeUserAsync(_testUserId, subscriptionDto, "new-agent", "192.168.1.2");
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
var updatedSubscription = await _context.PushSubscriptions.FirstOrDefaultAsync();
|
||||
Assert.NotNull(updatedSubscription);
|
||||
Assert.Equal("new-p256dh", updatedSubscription.P256DH);
|
||||
Assert.Equal("new-auth", updatedSubscription.Auth);
|
||||
Assert.Equal("new-agent", updatedSubscription.UserAgent);
|
||||
Assert.Equal("192.168.1.2", updatedSubscription.IpAddress);
|
||||
Assert.True(updatedSubscription.IsActive);
|
||||
Assert.NotNull(updatedSubscription.LastUsedAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SubscribeCustomerAsync_CreatesNewSubscription()
|
||||
{
|
||||
// Arrange
|
||||
var subscriptionDto = new PushSubscriptionDto
|
||||
{
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/customer-test",
|
||||
P256DH = "customer-p256dh",
|
||||
Auth = "customer-auth"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _service.SubscribeCustomerAsync(_testCustomerId, subscriptionDto);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
var subscription = await _context.PushSubscriptions.FirstOrDefaultAsync();
|
||||
Assert.NotNull(subscription);
|
||||
Assert.Equal(_testCustomerId, subscription.CustomerId);
|
||||
Assert.Equal(subscriptionDto.Endpoint, subscription.Endpoint);
|
||||
Assert.True(subscription.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnsubscribeAsync_DeactivatesSubscription()
|
||||
{
|
||||
// Arrange
|
||||
var subscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
_context.PushSubscriptions.Add(subscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Act
|
||||
var result = await _service.UnsubscribeAsync(subscription.Endpoint);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
var updatedSubscription = await _context.PushSubscriptions.FirstOrDefaultAsync();
|
||||
Assert.NotNull(updatedSubscription);
|
||||
Assert.False(updatedSubscription.IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UnsubscribeAsync_ReturnsFalse_WhenSubscriptionNotFound()
|
||||
{
|
||||
// Act
|
||||
var result = await _service.UnsubscribeAsync("non-existent-endpoint");
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetActiveSubscriptionsAsync_ReturnsOnlyActiveSubscriptions()
|
||||
{
|
||||
// Arrange
|
||||
var activeSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/active",
|
||||
P256DH = "active-p256dh",
|
||||
Auth = "active-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
var inactiveSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/inactive",
|
||||
P256DH = "inactive-p256dh",
|
||||
Auth = "inactive-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
IsActive = false
|
||||
};
|
||||
|
||||
_context.PushSubscriptions.AddRange(activeSubscription, inactiveSubscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Act
|
||||
var result = await _service.GetActiveSubscriptionsAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Single(result);
|
||||
Assert.Equal(activeSubscription.Endpoint, result.First().Endpoint);
|
||||
Assert.True(result.First().IsActive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CleanupExpiredSubscriptionsAsync_RemovesOldSubscriptions()
|
||||
{
|
||||
// Arrange
|
||||
var expiredSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/expired",
|
||||
P256DH = "expired-p256dh",
|
||||
Auth = "expired-auth",
|
||||
SubscribedAt = DateTime.UtcNow.AddDays(-35),
|
||||
LastUsedAt = DateTime.UtcNow.AddDays(-35),
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
var recentSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/recent",
|
||||
P256DH = "recent-p256dh",
|
||||
Auth = "recent-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
LastUsedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
var inactiveSubscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/inactive",
|
||||
P256DH = "inactive-p256dh",
|
||||
Auth = "inactive-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
LastUsedAt = DateTime.UtcNow,
|
||||
IsActive = false
|
||||
};
|
||||
|
||||
_context.PushSubscriptions.AddRange(expiredSubscription, recentSubscription, inactiveSubscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Act
|
||||
var cleanedCount = await _service.CleanupExpiredSubscriptionsAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, cleanedCount); // expired and inactive should be removed
|
||||
var remainingSubscriptions = await _context.PushSubscriptions.ToListAsync();
|
||||
Assert.Single(remainingSubscriptions);
|
||||
Assert.Equal(recentSubscription.Endpoint, remainingSubscriptions.First().Endpoint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendTestNotificationAsync_WithValidUserId_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var subscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
_context.PushSubscriptions.Add(subscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Note: This test will only verify the logic flow, not actual push sending
|
||||
// since that requires real push service endpoints
|
||||
|
||||
// Act & Assert
|
||||
// For now, we'll test that the method handles the case where no valid subscriptions exist
|
||||
var result = await _service.SendTestNotificationAsync(Guid.NewGuid().ToString());
|
||||
|
||||
// The method should complete without throwing exceptions
|
||||
Assert.False(result); // No subscriptions for non-existent user
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendTestNotificationAsync_WithoutUserId_SendsToAllAdmins()
|
||||
{
|
||||
// Arrange
|
||||
var subscription = new LittleShop.Models.PushSubscription
|
||||
{
|
||||
UserId = _testUserId,
|
||||
Endpoint = "https://fcm.googleapis.com/fcm/send/test",
|
||||
P256DH = "test-p256dh",
|
||||
Auth = "test-auth",
|
||||
SubscribedAt = DateTime.UtcNow,
|
||||
IsActive = true
|
||||
};
|
||||
_context.PushSubscriptions.Add(subscription);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Act & Assert
|
||||
// This will attempt to send to all admin users
|
||||
// The method should complete without throwing exceptions even if push fails
|
||||
var result = await _service.SendTestNotificationAsync();
|
||||
|
||||
// We expect false because we can't actually send push notifications in tests
|
||||
// but the method should handle the flow correctly
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user